[
  {
    "path": ".dockerignore",
    "content": "# Files for docker\ndocker-compose.yml\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.pyc\n*.pyo\n*.pyd\n*.local\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache/\n.hypothesis/\ncoverage.xml\n\n# IPython Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# virtualenv\nvenv/\nENV/\n.env/\n\n# pytest\n.pytest_cache/\n\n# IDE\n.idea/\n\n# mypy\n.mypy_cache/\n\n# VCS\n.git/\n.gitignore\n.gitattributes\n"
  },
  {
    "path": ".gitignore",
    "content": "# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n\n# IDE\n.idea/**\nsrc/.idea/**\n\n# CMake build\ncmake-build*\nbuild*\n\n# Byte-compiled Python\n__pycache__/\n\n# Python build stuff\n*.egg-info/**\n\n# RL-training related\ntrain_dir/\n\n# Python intermediate folders\nmegaverse/extension/**\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"src/3rdparty/googletest-1.10.0\"]\n\tpath = src/3rdparty/googletest-1.10.0\n\turl = https://github.com/google/googletest.git\n[submodule \"src/3rdparty/pybind11\"]\n\tpath = src/3rdparty/pybind11\n\turl = https://github.com/pybind/pybind11.git\n[submodule \"src/3rdparty/magnum\"]\n\tpath = src/3rdparty/magnum\n\turl = https://github.com/mosra/magnum.git\n[submodule \"src/3rdparty/corrade\"]\n\tpath = src/3rdparty/corrade\n\turl = https://github.com/mosra/corrade.git\n[submodule \"src/3rdparty/v4r\"]\n\tpath = src/3rdparty/v4r\n\turl = https://github.com/alex-petrenko/v4r.git\n[submodule \"src/3rdparty/magnum-integration\"]\n\tpath = src/3rdparty/magnum-integration\n\turl = https://github.com/mosra/magnum-integration.git\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Aleksei Petrenko\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": "MANIFEST.in",
    "content": "global-include *\nglobal-exclude *git*\nrecursive-exclude **/benchmark* *\nrecursive-exclude **/json/test *\nrecursive-exclude **/.git *\nprune dist"
  },
  {
    "path": "Makefile",
    "content": "PYTHON ?= python\n\nexport BASE_TAG=$(shell ${PYTHON} -c 'import hashlib; sha = hashlib.sha1((open(\"docker/Dockerfile.base\").read() + open(\"requirements/requirements.txt\").read()).encode()); print(sha.hexdigest())')\nBRANCH = $(shell git rev-parse --abbrev-ref HEAD)\nVERSION = $(shell git rev-parse --short HEAD)\nDATE = $(shell date +%F)\nexport TAG=$(BRANCH)-$(VERSION)-$(DATE)\n\n.PHONY: pull build up push shell docker-bash\n\npull-%:\n\tdocker-compose pull $(subst pull-,,$@)\n\nbuild-%:\n\tdocker-compose build $(subst build-,,$@)\n\nup-%:\n\tdocker-compose up -d $(subst up-,,$@)\n\npush-%:\n\tdocker-compose push $(subst push-,,$@)\n\nshell:\n\t@echo TAG=$(TAG) BASE_TAG=$(BASE_TAG)\n\ndocker-bash:\n\tdocker-compose run --it --rm dev bash\n\n.PHONY: upload upload-test clean\n\nupload:\n\tpython3 -m twine upload --repository pypi dist/*\n\nupload-test:\n\tpython3 -m twine upload --repository testpypi dist/*\n\nclean:\n\trm -rf build dist\n\n"
  },
  {
    "path": "README.md",
    "content": "# Megaverse\n\n[<img src=\"https://img.shields.io/discord/987232982798598164?label=discord\">](https://discord.gg/4ZNdhfaZtK)\n\nMegaverse is a dedicated high-throughput rendering and simulation engine for Artificial Intelligence research.\nIt features an optimized batched renderer that enables generation of up to 1,000,000 observations per second on a single machine.\n\n* **Website:** [www.megaverse.info](https://www.megaverse.info) \n* **arXiv:** [arxiv.org/abs/2107.08170](https://arxiv.org/abs/2107.08170)\n\nLeft: RL agent completing a TowerBuilding task. Right: human player solving a randomly generated obstacle course.\n\n<p align=\"middle\">\n<img src=\"https://github.com/alex-petrenko/megaverse/blob/master/data/tower_rl.gif?raw=true\" width=\"400\">\n<img src=\"https://github.com/alex-petrenko/megaverse/blob/master/data/obstacles_hard_play_x2.gif?raw=true\" width=\"400\">\n</p> \n\n## Installation\n\nCurrently, the easiest way to install Megaverse is to build directly from sources.\n\n### Linux\n\n\n```shell\n# 0) A completely clean Linux installation needs basic OpenGL libraries. The rest of the dependencies are installed with Conda and don't require elevated privileges.\n$ sudo apt install libgl1-mesa-dev libegl1-mesa-dev\n\n# 1) Install VulkanSDK from https://vulkan.lunarg.com/sdk/home#linux (download and unzip), or use the following commands:\n$ wget https://sdk.lunarg.com/sdk/download/1.2.198.1/linux/vulkansdk-linux-x86_64-1.2.198.1.tar.gz\n$ mkdir vulkansdk && tar -xzf vulkansdk-linux-x86_64-1.2.198.1.tar.gz --directory vulkansdk\n\n# 2) Add Vulkan SDK binaries to PATH (might need to do it each time recompiling Megaverse is required):\n$ cd vulkansdk/1.2.198.1\n$ source ./setup-env.sh\n\n# 3) Clone the repo\n$ git clone https://github.com/alex-petrenko/megaverse.git\n\n# 4) Init submodules\n$ cd megaverse \n$ git submodule update --init --recursive\n\n# 5) Create a conda environment and install dependencies\n$ conda create --name megaverse python=3.9\n$ conda activate megaverse\n(megaverse) $ conda install -c conda-forge 'opencv>=4.4,<4.5' 'cmake>=3.13' bullet cudatoolkit cudatoolkit-dev sdl2\n\n# (alternatively you can boostrap from an environment file: conda env create -f environment.yml)\n\n# 6) Install megaverse into a conda env\n(megaverse) $ python setup.py develop\n(megaverse) $ pip install -e .\n\n# (Optional) 6.1) Build a .whl file to be installed elsewhere\n(megaverse) $ python setup.py bdist_wheel\n```\n\n### macOS\n\nAlthough Vulkan-powered batched rendering is not supported on macOS, a limited OpenGL version can be built for\nlocal debugging and small-scale experiments on macOS.\nInstalling on mac is very similar to Linux, sans any Vulkan/CUDA dependencies.\n\n```shell\n# 1) Clone the repo\n$ git clone https://github.com/alex-petrenko/megaverse.git\n\n# 2) Init submodules\n$ cd megaverse \n$ git submodule update --init --recursive\n\n# 3) Create a conda environment and install dependencies\n$ conda create --name megaverse python=3.9\n$ conda activate megaverse\n(megaverse) $ conda install -c conda-forge 'opencv>=4.4,<4.5' 'cmake>=3.13' bullet\n\n# 4) Install megaverse into a conda env\n(megaverse) $ python setup.py develop\n(megaverse) $ pip install -e .\n\n# (Optional) 4.1) Build a .whl file to be installed elsewhere\n(megaverse) $ python setup.py bdist_wheel\n```\n\n### Docker \n\nSince installation does not require elevated priviliges, Docker setup is not required.\nHowever, Docker-based installation is also available, see here:\n[docker/README.md](https://github.com/alex-petrenko/megaverse/blob/master/docker/README.md).\n\n## Examples\n\n### Python API\n\nThe following script executes a random policy:\n\n```Python\nimport numpy as np\nfrom megaverse.megaverse_env import MegaverseEnv\n\n\nenv = MegaverseEnv(\n    'TowerBuilding',\n    num_envs=2, num_agents_per_env=2,\n    num_simulation_threads=4, use_vulkan=True,\n    params={},\n)\nenv.reset()\n\nwhile True:\n    actions = [env.action_space.sample() for _ in range(env.num_agents)]\n    obs, rewards, dones, infos = env.step(actions)\n    if np.any(dones):\n        break\n\n    env.render()\n\n```\n\n## RL Training\n\nExample training script using Sample Factory RL framework. First install the prerequisite:\n\n```\npip install \"sample-factory>=2.0\"\n```\n\n(this instruction was tested on version from branch `sf2`, commit f4b5e971f467fc8dcabc0adee8b1c04885412fbb,\n`pip install git+https://github.com/alex-petrenko/sample-factory.git@f4b5e971f467fc8dcabc0adee8b1c04885412fbb`)\n\nThen, to train agents in the TowerBuilding environment, execute:\n```\npython -m megaverse_rl.train_megaverse --train_for_seconds=360000000 --train_for_env_steps=2000000000 --algo=APPO --gamma=0.997 --use_rnn=True --rnn_num_layers=2 --num_workers=8 --num_envs_per_worker=2 --num_epochs=1 --rollout=32 --recurrence=32 --batch_size=4096 --actor_worker_gpus 0 --num_policies=1 --with_pbt=False --max_grad_norm=0.0 --exploration_loss=symmetric_kl --exploration_loss_coeff=0.001 --megaverse_num_simulation_threads=1 --megaverse_num_envs_per_instance=48 --megaverse_num_agents_per_env=1 --megaverse_use_vulkan=True --policy_workers_per_policy=2 --reward_clip=30 --env=TowerBuilding --experiment=TowerBuilding\n```\n\nObserve the behavior of agents by running:\n\n```\npython -m megaverse_rl.enjoy --algo=APPO --env=TowerBuilding --experiment=TowerBuilding --megaverse_num_envs_per_instance=1 --fps=20 --megaverse_use_vulkan=True\n```\n\nSee Sample Factory 2 documentation for additional information.\n\n## Development\n\n### Setting up a CMake project in IDE\n\nThe core functionality of Megaverse is implemented in C++ and uses CMake build system.\nThe easiest way to work on Megaverse C++ codebase is to use an IDE that can import a CMake project (defined by the root CMakeLists.txt in megaverse/src).\nAny such IDE would need to run `cmake` in order to build and debug the code.\nThus `cmake` needs to be able to find all the libraries installed through conda (such as Bullet and OpenCV).\n\nThe most straightforward way to make sure that libraries can be found is to start IDE directly from the conda environment we defined above (see section Installation/Linux).\nSpecifically, for CLion IDE it would look like this:\n\n```shell\n$ conda activate megaverse\n# navigate to Vulkan SDK installation dir\n(megaverse) $ cd vulkansdk-linux-x86_64-1.2.198.1/1.2.198.1/\n# make sure that Vulkan env variables are initialized\n(megaverse) $ source ./setup-env.sh\n# start the IDE from the terminal (assuming clion is in PATH, usually you can do this with Tools->Create Command-Line Launcher)\n(megaverse) $ clion & \n```\n\nNow in the IDE open megaverse/src/CMakeLists.txt as CMake project and you should be able to build and run targets.\n\n#### Running an IDE without Conda enviroment\n\nAlternatively, if IDE is not run from a conda environment we might need to explicitly specify paths to libraries in IDE's CMake command line\n(i.e. in CLion that would be `Settings -> Build,Execution,Deployment -> CMake -> CMake options`).\nYour CMake options might looks like this:\n\n```\n-DPYTHON_EXECUTABLE=/home/<user>/miniconda3/envs/megaverse/bin/python\n-DCMAKE_CUDA_COMPILER=/home/<user>/miniconda3/envs/megaverse/bin/nvcc\n-DOpenCV_DIR=/home/<user>/miniconda3/envs/megaverse/lib/cmake/opencv4\n-DBUILD_GUI_APPS=ON\n```\n\nAdditionally, an environment variable `VULKAN_SDK=/home/<user>/all/libs/vulkansdk-linux-x86_64-1.2.198.1/1.2.198.1/x86_64` must be set.\nIn most IDEs this can be set in the same CMake configuration dialogue.\n\nFinally, CMake should be able to find Bullet physics library. There are three ways to accomplish this:\n1. Install `libbullet-dev` and CMake will find the system-wide installation\n2. To link against `bullet` installed by Conda you need to make sure your IDE also uses Conda's `cmake`,\nrather than `cmake` bundled with the IDE. In CLion you can change this in `Settings -> Build,Execution,Deployment -> Toolchains -> CMake`.\nThis way `cmake` should be able to find Conda's Bullet CMake config `<env>/lib/cmake/bullet/BulletConfig.cmake`\n3. Alternatively, you can build Bullet from sources and add a CMake option `-DBULLET_ROOT` pointing to the correct location.\n\n### Notable build targets\n\nCMakeLists.txt defines many targets. The following targets are the most useful: \n\n* `megaverse` builds the overall project and the Python bindings (see setup.py)\n* `run_unit_tests` runs Google Tests (see `megaverse/src/test`)\n* `viewer_app` builds an interactive application that allows you to control agents with keyboard and explore environments with an overview camera.\nThis one is really designed to interact with a single environment at a time, and is very useful during development and debugging phase. See details below.\n* `megaverse_test_app` can use the parallel simulation engine and batch renderer to execute many environment at once. See details below.\n\n### Using viewer_app\n\n`viewer_app` can run any scenario in an interactive mode and offers a bunch of command line parameters:\n```\nUsage: viewer_app [options] \n\nOptional arguments:\n-h --help           \tshows help message and exits [default: false]\n-v --version        \tprints version information and exits [default: false]\n-l --list_scenarios \tlist registered scenario names [default: false]\n--scenario          \tname of the scenario to run [default: \"ObstaclesEasy\"]\n--num_agents        \tsize of the team, pass value 1 to have just a single agent [default: 2]\n--desired_fps       \trendering framerate for human perception; RL agents percieve the world at 15 FPS to avoid frameskip, hence the default value. [default: 15]\n--use_opengl        \tWhether to use OpenGL renderer instead of fast Vulkan renderer (currently Vulkan is only supported in Linux) [default: false]\n```\n\nOnce the app started, use keyboard to control the agent and the camera:\n* `WASD` and arrow keys to control the agent\n* `1,2,3,4,etc.` to switch between agents (if several are present in the environment)\n* Press `O` to toggle the overview camera, use mouse to control view angle\n* Use `UHJK` keys to control the position of the camera in the overview mode\n* Press `R` to reset the episode\n* Press `ENTER` to toggle Bullet collision debug view (only OpenGL version)\n* `ESC` to exit the app\n\n### Using megaverse_test_app\n\n`megaverse_test_app` uses parallel interface and is a much easier target to debug compared to Python Gym API. \n\n```\nusage: megaverse_test_app [options] \n\nThis app is designed to test the parallel execution engine and batched renderer\nby simulating multiple environments at once. This app uses pretty much the same interface\nas the Python Gym environment, sans the Python bindings. Whenever there is a problem\nwith the environment, it is much easier to debug this app directly, rather\nthan debugging the same code through Python.\n\nExample, render 12 agents at the same time:\nmegaverse_test_app --scenario Collect --visualize --num_envs 4 --num_simulation_threads 1 --num_agents 3 --hires\n\nSome performance figures for future reference (on 10-core Intel i9):\nmegaverse_test_app --scenario Empty --performance_test --num_envs 64 --num_simulation_threads 1 --num_agents 1\nyields approximately 75000 FPS\nmegaverse_test_app --scenario Collect --performance_test --num_envs 64 --num_simulation_threads 1 --num_agents 1\nyields approximately 27000 FPS\n\n\nOptional arguments:\n-h --help                \tshows help message and exits [default: false]\n-v --version             \tprints version information and exits [default: false]\n-l --list_scenarios      \tlist registered scenario names [default: false]\n--scenario               \tname of the scenario to run [default: \"ObstaclesEasy\"]\n--num_agents             \tsize of the team [default: 2]\n--use_opengl             \tWhether to use OpenGL renderer instead of fast Vulkan renderer (currently Vulkan is only supported in Linux) [default: false]\n--num_envs               \tnumber of parallel environments to simulate [default: 64]\n--num_simulation_threads \tnumber of parallel CPU threads to use for Bullet [default: 1]\n--visualize              \tWhether to render multiple environments on screen [default: false]\n--visualize              \tWhether to render multiple environments on screen [default: false]\n--delay_ms               \tDelay between rendered frames in milliseconds. Use only with --visualize [default: 1]\n--performance_test       \tRun for a limited number of env frames (currently 200000) to test performance. Uses random actions. [default: false]\n--hires                  \tRender at high resolution. Only use this parameter with --visualize and if the total number of agents is small [default: false]\n--user_actions           \tAllows the user to control agents (otherwise will use randomly generated actions). Use only with --visualize [default: false]\n```\n\n## Troubleshooting\n\n* A crash (segfault) on startup can be caused by the incorrect initialization of Vulkan device interface. Possible fixes:\n    * `sudo apt remove mesa-vulkan-drivers` (unless other packages you require depend on this package)\n    * Set envvar `export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json`, point to the location of `nvidia_icd.json` in your system.\n\n## Citation\n\nIf you use this repository in your work or otherwise wish to cite it, please make reference to our ICML2021 paper.\n\n```\n@inproceedings{petrenko2021megaverse,\n  title={Megaverse: Simulating Embodied Agents at One Million Experiences per Second},\n  author={Petrenko, Aleksei and Wijmans, Erik and Shacklett, Brennan and Koltun, Vladlen},\n  booktitle={ICML},\n  year={2021}\n}\n```\n\nFor questions, issues, inquiries please email apetrenko1991@gmail.com. \nGithub issues and pull requests are welcome.\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "data/benchmarking.txt",
    "content": "July 29th, 2020\n\nparallel -N0 './test_performance' ::: {1..20}\n30x30 grid of cubes instanced, 128x72\n11800 polygons\n\n1 core: 7596 FPS\n2 cores: 5815 * 2 = 11630 FPS\n4 cores: 3852 * 4 = 15408 FPS\n8 cores: 1950 * 8 = 15600 FPS\n10 cores: 1546 * 10 = 15460 FPS\n20 cores: 764 * 20 = 15280 FPS\n\n10x10 grid of cubes instanced, 128x72\n1200 polygons\n1 core: 36000 FPS\n2 cores: 9253 * 2 = 18506 FPS\n3 cores: 6211 * 3 = 18633 FPS\n4 cores: 4619 * 4 = 18476 FPS\n10 cores: 1796 * 10 = 17960 FPS\n\n\nparallel -N0 './test_performance --magnum-device 2 --magnum-log verbose' ::: {1..10}\n30x30 grid of cubes instanced, 128x72\n11800 polygons\nsoftware rendering\n\n1 core: 440 FPS\n2 cores: 481 * 2 = 962 FPS\n4 cores: 468 * 4 = 1872 FPS\n8 cores: 429 * 8 = 3432 FPS\n10 cores: 411 * 10 = 4110 FPS\n20 cores: 286 * 20 = 5720 FPS\n\n10x10 grid of cubes instanced, 128x72\n1200 polygons\nsoftware rendering\n\n1 core: 2464 FPS\n2 cores: 2047 * 2 = 4094 FPS\n4 cores: 2087 * 4 = 8348 FPS\n10 cores: 1706 * 10 = 17060 FPS\n20 cores: 1248 * 20 = 24960 FPS\n"
  },
  {
    "path": "data/old_readme.md",
    "content": "Previous Readme\n```\n1) Clone the repo\ngit clone https://github.com/alex-petrenko/megaverse.git\n\n2) Init submodules\ngit submodule update --init --recursive\n\n3) Clone and build OpenCV (also possible to use OpenCV installed from Conda)\ncd ~/lib\ngit clone https://github.com/opencv/opencv.git\ncd opencv\nmkdir build\ncmake -D CMAKE_BUILD_TYPE=Release ..\nmake -j10\n\n4) Install CUDA 10.2\nhttps://developer.nvidia.com/cuda-10.2-download-archive\n\n5) Install Vulkan\n\nwget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -\nsudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.2.154-bionic.list https://packages.lunarg.com/vulkan/1.2.154/lunarg-vulkan-1.2.154-bionic.list\nsudo apt update\nsudo apt install vulkan-sdk\n\n(or install manually from https://vulkan.lunarg.com/sdk/home#linux, then source ./setup-env.sh to set envvars) \n\n6) Setup Python environment (TODO: add environment.yml to this repo, currently using one from Sample Factory)\n(REQUIRES: opencv, cudatoolkit\nconda install -c conda-forge opencv\nconda install -c anaconda cudatoolkit\nconda install -c conda-forge cudatoolkit-dev\n)\n\n\ngit clone https://github.com/alex-petrenko/sample-factory.git\ncd sample-factory\nconda env create -f environment.yml\nconda activate sample-factory\n\n7) Install PyBullet\nconda install -c conda-forge bullet\n(preferred)\n\nOR\n\nsudo apt install libbullet-dev \n\n8) Update CMake if necessary (version 3.13 or newer is required)\n\nconda install -c anaconda cmake\n(preferred)\n\nOR\n\nsudo apt remove --purge cmake\nhash -r\nsudo snap install cmake --classic\n\n9) Build the repo\ncd megaverse\nmkdir build\ncd build\n\n# Run CMake, specify the OpenCV build dir and Python3 executable (e.g. from a conda environment)\ncmake -DCMAKE_BUILD_TYPE=Release  \\\n-DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \\\n-DPYTHON_EXECUTABLE:FILEPATH=/home/<user>/miniconda3/envs/<envname>/bin/python3.7 \\\n../src\n\n(optionally, add -DBULLET_ROOT=/home/<user>/lib/bullet3-2.89/install if you built it from sources)\n(optionally, add -DOpenCV_DIR=/home/<user>/lib/opencv/build if you built it from sources)\n\n# Build all targets\nmake -j10\n\n10) Run benchmark\ncd Release/bin\n./megaverse_test_app\n\n(see global boolean flags in megaverse_test_app.cpp, they control the scenario and rendering settings\nTODO: make configurable)\n\n11) Run viewer\ncd Release/bin\n./viewer_app\n\nuse WASD and arrows to control agent\ndigits (1,2) to switch between agents in multi-agent envs\nE to interact with objects\nO to switch to overview camera\nUHJK to control overview camera\n\n(see global vars at the top of viewer_app.cpp file to control which environment is chosen\nTODO: make configurable)\n\n12) To build the Python package and install it in the active Python env:\npython setup.py develop\npip install -e .\n\n13) Run tests\npython -m unittest\n\n14) You are ready to use the Megaverse Python API!\n\n```\n\nTraining:\n\n```\n\nSingle experiment example:\n\npython -m megaverse_rl.train_megaverse --train_for_seconds=360000000 --train_for_env_steps=2000000000 --algo=APPO --gamma=0.997 --use_rnn=True --rnn_num_layers=2 --num_workers=12 --num_envs_per_worker=2 --num_epochs=1 --rollout=32 --recurrence=32 --batch_size=2048 --actor_worker_gpus 0 --num_policies=1 --with_pbt=False --max_grad_norm=0.0 --exploration_loss=symmetric_kl --exploration_loss_coeff=0.001 --voxel_num_simulation_threads=1 --voxel_use_vulkan=True --policy_workers_per_policy=2 --reward_clip=30 --env=voxel_env_TowerBuilding --experiment=test_cli\n\nExample runner script:\n\npython -m sample_factory.runner.run --run=megaverse_rl.runs.megaverse_single_agent --runner=processes --max_parallel=8 --pause_between=10 --experiments_per_gpu=2 --num_gpus=4\n\n\n```\n\n\nDocker setup:\n\n```\nInstall docker-compose:\n\npip install docker-compose\n\n\n```"
  },
  {
    "path": "docker/Dockerfile.base",
    "content": "FROM nvidia/cudagl:10.2-devel-ubuntu18.04\n# FROM nvidia/cudagl:11.0-devel-ubuntu20.04\n# FROM nvidia/cuda:10.2-cudnn7-devel-ubuntu18.04\n\n# Set up locale to prevent bugs with encoding\nENV LC_ALL=C.UTF-8 LANG=C.UTF-8\n\nRUN apt-get update || true && apt-get install -y \\\n    libcudnn8 \\\n    libglvnd0 libgl1 libglx0 libegl1 \\\n    libglvnd-dev libgl1-mesa-dev libegl1-mesa-dev \\\n    wget curl git zlib1g-dev \\\n    libglib2.0-0 libsm6 libxext6 libxrender-dev \\\n    python3 python3-pip cmake \\\n    && apt-get clean \\\n    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*\n\nWORKDIR /vulkan\nRUN wget https://sdk.lunarg.com/sdk/download/1.2.162.0/linux/vulkansdk-linux-x86_64-1.2.162.0.tar.gz && tar -xzf vulkansdk-linux-x86_64-1.2.162.0.tar.gz\n\nENV VULKAN_SDK=/vulkan/1.2.162.0/x86_64\nENV PATH=${VULKAN_SDK}/bin:${PATH}\nENV LD_LIBRARY_PATH=${VULKAN_SDK}/lib:${LD_LIBRARY_PATH:-}\nENV VK_LAYER_PATH=${VULKAN_SDK}/etc/vulkan/explicit_layer.d\n\nRUN vulkaninfo\n\nWORKDIR /\n\nRUN cd /usr/bin \\\n    && ln -s python3 python \\\n    && ln -s pip3 pip\n\nRUN curl -LO http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh && \\\n    bash Miniconda3-latest-Linux-x86_64.sh -p /miniconda -b && \\\n    rm Miniconda3-latest-Linux-x86_64.sh\n\nENV PATH=/miniconda/bin:${PATH}\nRUN conda update -y conda && conda --version\n\nWORKDIR /workspace\n\nRUN git clone https://github.com/alex-petrenko/sample-factory.git\nRUN git clone https://github.com/alex-petrenko/megaverse.git\nWORKDIR sample-factory\n\nRUN conda env create -f environment.yml\nRUN conda init bash\nSHELL [\"conda\", \"run\", \"-n\", \"sample-factory\", \"/bin/bash\", \"-c\"]\nRUN conda install -n sample-factory -c anaconda cudatoolkit cmake\nRUN conda install -n sample-factory -c conda-forge opencv bullet cudatoolkit-dev\nRUN pip install -e .\n\nWORKDIR /workspace/megaverse\n\nRUN git submodule update --init --recursive\n\nRUN pip install -e .\n\n"
  },
  {
    "path": "docker/README.md",
    "content": "### Docker instructions\n\n```\n1) Clone the repo \n$ git clone https://github.com/alex-petrenko/megaverse.git\n\n2) Build the image\ncd megaverse\ndocker build -t megaverse -f docker/Dockerfile.base .\n\n3) Start megaverse\ndocker run --shm-size 8G --runtime=nvidia megaverse ./docker/run.sh\n\n(Optional) 4) Launch bash in the container and enjoy\ndocker run -it --shm-size 8G --runtime=nvidia --entrypoint /bin/bash megaverse\n```"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: \"3.3\"\n\nservices:\n\n# base\n  base:\n    image: \"${REPO}-base:${BASE_TAG}\"\n    build:\n      context: .\n      dockerfile: docker/Dockerfile.base\n\n# dev\n  dev:\n    image: \"${REPO}-dev:${BASE_TAG}\"\n    depends_on:\n      - base\n    build:\n      context: .\n      dockerfile: docker/Dockerfile.dev\n      args:\n        REPO: ${REPO}\n        BASE_TAG: ${BASE_TAG}\n    volumes:\n      - \".:/workspace\"\n"
  },
  {
    "path": "environment.yml",
    "content": "name: megaverse\nchannels:\n  - pytorch\n  - anaconda\n  - conda-forge\n  - defaults\ndependencies:\n  - _libgcc_mutex=0.1=main\n  - blas=1.0=mkl\n  - bullet=2.89=py38hc5bc63f_1\n  - bzip2=1.0.8=h516909a_2\n  - ca-certificates=2020.10.14=0\n  - cairo=1.16.0=hcf35c78_1003\n  - certifi=2020.6.20=py38_0\n  - cmake=3.18.2=ha30ef3c_0\n  - cudatoolkit=10.2.89=hfd86e86_1\n  - cudatoolkit-dev=11.0.3=py38h497a2fe_2\n  - dbus=1.13.6=he372182_0\n  - expat=2.2.9=he1b5a44_2\n  - ffmpeg=4.3.1=h167e202_0\n  - fontconfig=2.13.1=h86ecdb6_1001\n  - freetype=2.10.2=h5ab3b9f_0\n  - gettext=0.19.8.1=hc5be6a0_1002\n  - glib=2.65.0=h6f030ca_0\n  - gmp=6.2.0=he1b5a44_2\n  - gnutls=3.6.13=h79a8f9a_0\n  - graphite2=1.3.13=he1b5a44_1001\n  - gst-plugins-base=1.14.5=h0935bb2_2\n  - gstreamer=1.14.5=h36ae1b5_2\n  - harfbuzz=2.4.0=h9f30f68_3\n  - hdf5=1.10.6=nompi_h3c11f04_101\n  - icu=64.2=he1b5a44_1\n  - intel-openmp=2020.1=217\n  - jasper=1.900.1=h07fcdf6_1006\n  - jpeg=9d=h516909a_0\n  - krb5=1.18.2=h173b8e3_0\n  - lame=3.100=h14c3975_1001\n  - lcms2=2.11=h396b838_0\n  - ld_impl_linux-64=2.34=hc38a660_9\n  - libblas=3.8.0=16_mkl\n  - libcblas=3.8.0=16_mkl\n  - libclang=9.0.1=default_hde54327_0\n  - libcurl=7.71.1=h20c2e04_1\n  - libedit=3.1.20191231=h14c3975_1\n  - libffi=3.2.1=he1b5a44_1007\n  - libgcc-ng=9.1.0=hdf63c60_0\n  - libgfortran-ng=7.5.0=hdf63c60_14\n  - libiconv=1.15=h516909a_1006\n  - liblapack=3.8.0=16_mkl\n  - liblapacke=3.8.0=16_mkl\n  - libllvm9=9.0.1=he513fc3_1\n  - libopencv=4.4.0=py38_2\n  - libpng=1.6.37=hbc83047_0\n  - libssh2=1.9.0=h1ba5d50_1\n  - libstdcxx-ng=9.1.0=hdf63c60_0\n  - libtiff=4.1.0=h2733197_1\n  - libuuid=2.32.1=h14c3975_1000\n  - libuv=1.40.0=h7b6447c_0\n  - libwebp-base=1.1.0=h516909a_3\n  - libxcb=1.13=h14c3975_1002\n  - libxkbcommon=0.10.0=he1b5a44_0\n  - libxml2=2.9.10=hee79883_0\n  - lz4-c=1.9.2=he6710b0_1\n  - mkl=2020.1=217\n  - mkl-service=2.3.0=py38he904b0f_0\n  - mkl_fft=1.1.0=py38h23d657b_0\n  - mkl_random=1.1.1=py38h0573a6f_0\n  - ncurses=6.2=he6710b0_1\n  - nettle=3.4.1=h1bed415_1002\n  - ninja=1.10.0=py38hfd86e86_0\n  - nspr=4.27=he1b5a44_1\n  - nss=3.55=he751ad9_0\n  - numpy=1.19.1=py38hbc911f0_0\n  - numpy-base=1.19.1=py38hfa32c7d_0\n  - olefile=0.46=py_0\n  - opencv=4.4.0=py38_2\n  - openh264=2.1.1=h8b12597_0\n  - openssl=1.1.1h=h7b6447c_0\n  - pcre=8.44=he1b5a44_0\n  - pillow=7.2.0=py38hb39fc2d_0\n  - pip=20.2.1=py38_0\n  - pixman=0.38.0=h516909a_1003\n  - pthread-stubs=0.4=h14c3975_1001\n  - py-opencv=4.4.0=py38h23f93f0_2\n  - python=3.8.5=h4d41432_2_cpython\n  - python_abi=3.8=1_cp38\n  - pytorch=1.6.0=py3.8_cuda10.2.89_cudnn7.6.5_0\n  - qt=5.12.5=hd8c4c69_1\n  - readline=8.0=h7b6447c_0\n  - rhash=1.4.0=h1ba5d50_0\n  - setuptools=49.2.0=py38_0\n  - six=1.15.0=py_0\n  - sqlite=3.32.3=h62c20be_0\n  - tk=8.6.10=hbc83047_0\n  - torchvision=0.7.0=py38_cu102\n  - wheel=0.34.2=py38_0\n  - x264=1!152.20180806=h14c3975_0\n  - xorg-kbproto=1.0.7=h14c3975_1002\n  - xorg-libice=1.0.10=h516909a_0\n  - xorg-libsm=1.2.3=h84519dc_1000\n  - xorg-libx11=1.6.11=h516909a_0\n  - xorg-libxau=1.0.9=h14c3975_0\n  - xorg-libxdmcp=1.1.3=h516909a_0\n  - xorg-libxext=1.3.4=h516909a_0\n  - xorg-libxrender=0.9.10=h516909a_1002\n  - xorg-renderproto=0.11.1=h14c3975_1002\n  - xorg-xextproto=7.3.0=h14c3975_1002\n  - xorg-xproto=7.0.31=h14c3975_1007\n  - xz=5.2.5=h7b6447c_0\n  - zlib=1.2.11=h7b6447c_3\n  - zstd=1.4.5=h9ceee32_0\n  - pip:\n    - absl-py==0.9.0\n    - atari-py==0.2.6\n    - cloudpickle==1.3.0\n    - colorlog==4.2.1\n    - cython==0.29.23\n    - faster-fifo==1.2.0\n    - filelock==3.0.12\n    - future==0.18.2\n    - grpcio==1.31.0\n    - gym==0.17.2\n    - markdown==3.2.2\n    - opencv-python==4.5.2.54\n    - protobuf==3.12.4\n    - psutil==5.7.2\n    - pyglet==1.5.0\n    - scipy==1.5.2\n    - tensorboard==1.15.0\n    - tensorboardx==2.0\n    - threadpoolctl==2.1.0\n    - werkzeug==1.0.1\nprefix: /home/boyuan/miniconda3/envs/megaverse\n"
  },
  {
    "path": "megaverse/.gitignore",
    "content": ".idea/**\n__pycache__\n"
  },
  {
    "path": "megaverse/__init__.py",
    "content": ""
  },
  {
    "path": "megaverse/examples/__init__.py",
    "content": ""
  },
  {
    "path": "megaverse/examples/random_policy.py",
    "content": "import numpy as np\nfrom megaverse.megaverse_env import MegaverseEnv\n\n\nenv = MegaverseEnv(\n    'ObstaclesHard',\n    num_envs=2, num_agents_per_env=2,\n    num_simulation_threads=4, use_vulkan=True,\n    params={},\n)\nenv.reset()\n\nwhile True:\n    actions = [env.action_space.sample() for _ in range(env.num_agents)]\n    obs, rewards, dones, infos = env.step(actions)\n    if np.any(dones):\n        break\n\n    env.render()\n\nenv.close()\n"
  },
  {
    "path": "megaverse/megaverse_env.py",
    "content": "import cv2\nimport gym\nimport numpy as np\n\nfrom gym.spaces import Discrete\n\n# noinspection PyUnresolvedReferences\nfrom megaverse.extension.megaverse import MegaverseGym, set_megaverse_log_level\n\n\nMEGAVERSE8 = [\n    'TowerBuilding',\n    'ObstaclesEasy',\n    'ObstaclesHard',\n    'Collect',\n    'Sokoban',\n    'HexMemory',\n    'HexExplore',\n    'Rearrange',\n]\n\nOBSTACLES_MULTITASK = [\n    'ObstaclesWalls', 'ObstaclesSteps', 'ObstaclesLava', 'ObstaclesEasy', 'ObstaclesHard',\n]\n\n\ndef make_env_multitask(multitask_name, task_idx, num_envs, num_agents_per_env, num_simulation_threads, use_vulkan=False, params=None):\n    assert 'multitask' in multitask_name\n    if multitask_name.endswith('megaverse8'):\n        tasks = MEGAVERSE8\n    elif multitask_name.endswith('obstacles'):\n        tasks = OBSTACLES_MULTITASK\n    else:\n        raise NotImplementedError()\n\n    scenario_idx = task_idx % len(tasks)\n    scenario = tasks[scenario_idx]\n    print('Multi-task, scenario', scenario_idx, scenario)\n    return MegaverseEnv(scenario, num_envs, num_agents_per_env, num_simulation_threads, use_vulkan, params)\n\n\nclass MegaverseEnv(gym.Env):\n    def __init__(self, scenario_name, num_envs, num_agents_per_env, num_simulation_threads, use_vulkan=False, params=None):\n        scenario_name = scenario_name.casefold()\n        self.scenario_name = scenario_name\n\n        self.is_multiagent = True\n\n        set_megaverse_log_level(2)\n\n        self.img_w = 128\n        self.img_h = 72\n        self.channels = 3\n\n        self.use_vulkan = use_vulkan\n\n        # total number of simulated agents\n        self.num_agents = num_envs * num_agents_per_env\n        self.num_envs = num_envs\n        self.num_agents_per_env = num_agents_per_env\n\n        float_params = {}\n        if params is not None:\n            for k, v in params.items():\n                if isinstance(v, float):\n                    float_params[k] = v\n                else:\n                    raise Exception('Params of type %r not supported', type(v))\n\n        # float_params['episodeLengthSec'] = 1.0\n\n        self.env = MegaverseGym(\n            self.scenario_name,\n            self.img_w, self.img_h, num_envs, num_agents_per_env, num_simulation_threads, use_vulkan, float_params,\n        )\n\n        # obtaining default reward shaping scheme\n        self.default_shaping_scheme = self.env.get_reward_shaping(0, 0)\n\n        self.action_space = self.generate_action_space(self.env.action_space_sizes())\n        self.observation_space = gym.spaces.Box(0, 255, (self.channels, self.img_h, self.img_w), dtype=np.uint8)\n\n    @staticmethod\n    def generate_action_space(action_space_sizes):\n        \"\"\"\n        Left = 1 << 1,\n        Right = 1 << 2,\n\n        Forward = 1 << 3,\n        Backward = 1 << 4,\n\n        LookLeft = 1 << 5,\n        LookRight = 1 << 6,\n\n        Jump = 1 << 7,\n        Interact = 1 << 8,\n\n        LookDown = 1 << 9,\n        LookUp = 1 << 10,\n        \"\"\"\n        # spaces = [\n        #     Discrete(3),  # noop, go left, go right\n        #     Discrete(3),  # noop, forward, backward\n        #     Discrete(3),  # noop, look left, look right\n        #     Discrete(2),  # noop, jump\n        #     Discrete(2),  # noop, interact\n        #     Discrete(3),  # noop, look down, look up\n        # ]\n\n        spaces = [Discrete(sz) for sz in action_space_sizes]\n        space = gym.spaces.Tuple(spaces)\n        return space\n\n    def seed(self, seed=None):\n        if seed is None:\n            return\n\n        assert isinstance(seed, int), 'Expect seed to be an integer'\n        self.env.seed(seed)\n\n    def observations(self):\n        obs = []\n        for env_i in range(self.num_envs):\n            for agent_i in range(self.num_agents_per_env):\n                o = self.env.get_observation(env_i, agent_i)\n                o = o[:, :, :3]\n                o = np.transpose(o, (2, 0, 1))  # convert to CHW for PyTorch\n                obs.append(o)\n\n        return obs\n\n    def reset(self):\n        self.env.reset()\n        return self.observations()\n\n    def step(self, actions):\n        action_idx = 0\n        for env_i in range(self.num_envs):\n            for agent_i in range(self.num_agents_per_env):\n                self.env.set_actions(env_i, agent_i, actions[action_idx])\n                action_idx += 1\n\n        self.env.step()\n\n        dones, infos = [], []\n\n        agent_i = 0\n        for env_i in range(self.num_envs):\n            done = self.env.is_done(env_i)  # currently no individual done per agent\n            dones.extend([done for _ in range(self.num_agents_per_env)])\n            if done:\n                infos.extend([dict(true_reward=float(self.env.true_objective(env_i, j))) for j in range(self.num_agents_per_env)])\n            else:\n                infos.extend([{} for _ in range(self.num_agents_per_env)])\n\n            agent_i += self.num_agents_per_env\n\n        rewards = self.env.get_last_rewards()\n\n        obs = self.observations()\n\n        return obs, rewards, dones, infos\n\n    def convert_obs(self, obs):\n        if not self.use_vulkan:\n            obs = cv2.flip(obs, 0)\n        obs = cv2.cvtColor(obs, cv2.COLOR_RGB2BGR)\n        return obs\n\n    def render(self, mode='human'):\n        self.env.draw_overview()\n\n        self.env.draw_hires()\n\n        rows = []\n        for env_i in range(self.num_envs):\n            obs = [self.convert_obs(self.env.get_hires_observation(env_i, i)) for i in range(self.num_agents_per_env)]\n            obs_concat = np.concatenate(obs, axis=1)\n            rows.append(obs_concat)\n\n        obs_final = np.concatenate(rows, axis=0)\n        cv2.imshow(f'agent_{id(self)}', obs_final)\n        cv2.waitKey(1)\n        return obs_final\n\n    def get_default_reward_shaping(self):\n        return self.default_shaping_scheme\n\n    def get_current_reward_shaping(self, actor_idx: int):\n        env_idx = actor_idx // self.num_agents_per_env\n        agent_idx = actor_idx % self.num_agents_per_env\n        return self.env.get_reward_shaping(env_idx, agent_idx)\n\n    def set_reward_shaping(self, reward_shaping: dict, actor_idx: int):\n        env_idx = actor_idx // self.num_agents_per_env\n        agent_idx = actor_idx % self.num_agents_per_env\n        return self.env.set_reward_shaping(env_idx, agent_idx, reward_shaping)\n\n    def close(self):\n        if self.env:\n            self.env.close()\n"
  },
  {
    "path": "megaverse/tests/__init__.py",
    "content": ""
  },
  {
    "path": "megaverse/tests/test_env.py",
    "content": "import copy\nimport os\nimport time\n\nimport numpy as np\n\nfrom unittest import TestCase\n\nfrom megaverse.megaverse_env import MegaverseEnv, make_env_multitask\n\n\ndef sample_actions(e):\n    return [e.action_space.sample() for _ in range(e.num_agents)]\n\n\ndef make_test_env(num_envs, num_agents_per_env, num_simulation_threads, use_vulkan=False, params=None):\n    \"\"\"Making env with a default scenario name.\"\"\"\n    return MegaverseEnv('ObstaclesEasy', num_envs, num_agents_per_env, num_simulation_threads, use_vulkan, params)\n\n\nclass TestEnv(TestCase):\n    def test_env(self):\n        e = make_test_env(num_envs=1, num_agents_per_env=1, num_simulation_threads=1)\n        o = e.reset()\n        o = e.step(sample_actions(e))\n        e.close()\n\n    def test_env_close_immediately(self):\n        e = make_test_env(1, 1, 1)\n        e.close()\n\n    def test_two_envs_same_process(self):\n        e1 = make_test_env(1, 1, 1)\n        e2 = make_test_env(1, 1, 1)\n\n        e1.reset()\n        e2.reset()\n\n        e1.close()\n        e2.close()\n\n    def test_seeds(self):\n        e1 = make_test_env(1, 1, 1)\n        e1.seed(42)\n        e2 = make_test_env(1, 1, 1)\n        e2.seed(42)\n\n        obs1 = e1.reset()\n        obs2 = e2.reset()\n\n        self.assertTrue(np.array_equal(obs1, obs2))\n        e2.close()\n        e1.close()\n\n        # after this we have randomness due to physics?\n\n    def rendering(self, use_vulkan, episode_length_sec=60.0):\n        params = {'episodeLengthSec': episode_length_sec}\n\n        e1 = make_test_env(num_envs=2, num_agents_per_env=2, num_simulation_threads=2, use_vulkan=use_vulkan, params=params)\n        e2 = make_test_env(num_envs=1, num_agents_per_env=1, num_simulation_threads=1, use_vulkan=use_vulkan, params=params)\n\n        e1.reset()\n        e2.reset()\n\n        e1.render()\n        e2.render()\n\n        for i in range(100):\n            e1.step(sample_actions(e1))\n            e1.render()\n            e2.step(sample_actions(e2))\n            e2.render()\n\n        e2.close()\n        e1.close()\n\n    def test_render(self):\n        self.rendering(use_vulkan=False)\n\n    def test_render_vulkan(self):\n        self.rendering(use_vulkan=True)\n\n    def test_render_reset(self):\n        self.rendering(use_vulkan=False, episode_length_sec=1.0)\n\n    def test_render_vulkan_reset(self):\n        self.rendering(use_vulkan=True, episode_length_sec=1.0)\n\n    @staticmethod\n    def performance_num_envs(n, n_steps=5000):\n        print(f'Performance {n} {n_steps}')\n        envs = [make_test_env(1, 1, 1, use_vulkan=True) for _ in range(n)]\n        for e in envs:\n            e.seed(42)\n            e.reset()\n\n        total_reward = 0.0\n        actions = sample_actions(envs[0])\n        start = time.time()\n        for step in range(n_steps):\n            for i, e in enumerate(envs):\n                obs, rew, dones, infos = e.step(actions)\n                total_reward += sum(rew)\n                if all(dones):\n                    print(f'Episode boundary env {i}')\n        end = time.time()\n        elapsed = end - start\n        fps = envs[0].num_agents * n * n_steps / elapsed\n        print(f'Time {elapsed:.3f}, fps: {fps:.1f}, total reward: {total_reward:.3f}')\n\n        for e in envs:\n            e.close()\n        return fps\n\n    def test_performance(self):\n        fps1 = self.performance_num_envs(1)\n        fps2 = self.performance_num_envs(2)\n        fps4 = self.performance_num_envs(4)\n\n        # print(fps1, fps2, fps4)\n\n    def test_reward_shaping(self):\n        e = MegaverseEnv('TowerBuilding', num_envs=3, num_agents_per_env=2, num_simulation_threads=2, use_vulkan=True)\n        default_reward_shaping = e.get_default_reward_shaping()\n        self.assertEqual(default_reward_shaping, e.get_current_reward_shaping(0))\n        self.assertEqual(default_reward_shaping, e.get_current_reward_shaping(1))\n        self.assertEqual(default_reward_shaping, e.get_current_reward_shaping(2))\n        self.assertEqual(default_reward_shaping, e.get_current_reward_shaping(5))\n\n        new_reward_shaping = copy.deepcopy(default_reward_shaping)\n        for k, v in new_reward_shaping.items():\n            new_reward_shaping[k] = v * 3\n        e.set_reward_shaping(new_reward_shaping, 3)\n\n        self.assertEqual(default_reward_shaping, e.get_current_reward_shaping(0))\n        self.assertEqual(default_reward_shaping, e.get_current_reward_shaping(1))\n        self.assertNotEqual(default_reward_shaping, e.get_current_reward_shaping(3))\n\n        e.close()\n\n    def test_memleak(self):\n        def mem_usage_kb():\n            import psutil\n            process = psutil.Process(os.getpid())\n            return process.memory_info().rss / 1024\n\n        # params = {'episodeLengthSec': 0.1}\n        params = {}\n        e = MegaverseEnv('Rearrange', num_envs=32, num_agents_per_env=1, num_simulation_threads=1, use_vulkan=True, params=params)\n        e.reset()\n\n        orig_mem_usage = mem_usage_kb()\n\n        for i in range(1000):\n            print('Mem difference: ', mem_usage_kb() - orig_mem_usage, 'kb')\n            e.step(sample_actions(e))\n\n        print('Final mem difference: ', mem_usage_kb() - orig_mem_usage, 'kb')\n\n        e.close()\n\n    def test_multitask(self):\n        import multiprocessing as mp\n        num_processes = 2\n\n        def run_single_task(i):\n            e = make_env_multitask('megaverse8', i, 1, 1, 1, use_vulkan=True, params={})\n            e.reset()\n            e.render()  # TODO: if this call is omitted we have rendering bugs. Fixme!\n\n            for _ in range(1000):\n                e.step(sample_actions(e))\n                e.render()\n\n            e.close()\n\n        processes = []\n        for process_idx in range(num_processes):\n            p = mp.Process(target=run_single_task, args=(process_idx, ))\n            p.start()\n            processes.append(p)\n\n        for p in processes:\n            p.join()\n\n    def test_viewer(self):\n        params = {'episodeLengthSec': 1.0}\n        e1 = MegaverseEnv('ObstaclesHard', 2, 2, 2, True, params)\n        e1.reset()\n        e1.render()\n\n        for i in range(500):\n            e1.step(sample_actions(e1))\n            e1.render()\n            time.sleep(0.01)\n\n        e1.close()\n"
  },
  {
    "path": "megaverse_rl/__init__.py",
    "content": ""
  },
  {
    "path": "megaverse_rl/enjoy_megaverse.py",
    "content": "import sys\n\nfrom sample_factory.enjoy import enjoy\nfrom megaverse_rl.train_megaverse import parse_megaverse_args, register_megaverse_components\n\n\ndef main():\n    \"\"\"Script entry point.\"\"\"\n    register_megaverse_components()\n    cfg = parse_megaverse_args(evaluation=True)\n\n    status = enjoy(cfg)\n    return status\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n"
  },
  {
    "path": "megaverse_rl/megaverse_params.py",
    "content": "from sample_factory.utils.utils import str2bool\n\n\ndef megaverse_override_defaults(env, parser):\n    \"\"\"RL params specific to Megaverse envs.\"\"\"\n    parser.set_defaults(\n        encoder_type=\"conv\",\n        encoder_subtype=\"convnet_simple\",\n        hidden_size=512,\n        obs_subtract_mean=0.0,\n        obs_scale=255.0,\n        actor_worker_gpus=[0],  # rollout workers need GPUs to render (provide a list of GPUs to use)\n        env_gpu_actions=False,  # but OpenAI Gym interface is entirely CPU-based\n        env_gpu_observations=False,  # (which can actually be optimized for even higher throughput)\n        exploration_loss=\"symmetric_kl\",\n        exploration_loss_coeff=0.001,\n        normalize_input=True,\n        normalize_returns=True,\n        with_vtrace=False,\n    )\n\n\ndef add_megaverse_args(env, parser):\n    p = parser\n    p.add_argument(\n        \"--megaverse_num_envs_per_instance\", default=1, type=int, help=\"Num simulated envs per instance of Megaverse\"\n    )\n    p.add_argument(\n        \"--megaverse_num_agents_per_env\",\n        default=4,\n        type=int,\n        help=\"Number of agents in a single env withing a Megaverse instance. Total number of agents in one Megaverse = num_envs_per_instance * num_agents_per_env\",\n    )\n    p.add_argument(\n        \"--megaverse_num_simulation_threads\",\n        default=1,\n        type=int,\n        help=\"Number of CPU threads to use per instance of Megaverse\",\n    )\n    p.add_argument(\"--megaverse_use_vulkan\", default=True, type=str2bool, help=\"Whether to use Vulkan renderer\")\n\n    # Team Spirit options\n    p.add_argument(\n        \"--megaverse_increase_team_spirit\",\n        default=False,\n        type=str2bool,\n        help=\"Increase team spirit from 0 to 1 over max_team_spirit_steps during training. At 1, the reward will be completely selfless.\",\n    )\n    p.add_argument(\n        \"--megaverse_max_team_spirit_steps\",\n        default=1e9,\n        type=float,\n        help=\"Number of training steps when team spirit will hit 1.\",\n    )\n"
  },
  {
    "path": "megaverse_rl/megaverse_utils.py",
    "content": "from typing import Optional\n\nimport gym\nfrom megaverse.megaverse_env import MegaverseEnv, make_env_multitask\n\nfrom sample_factory.envs.env_utils import RewardShapingInterface, TrainingInfoInterface\nfrom sample_factory.utils.utils import log\n\n\nclass MegaverseSpec:\n    def __init__(self, name):\n        self.name = name\n\n\nMEGAVERSE_ENVS = [\n    MegaverseSpec(\"TowerBuilding\"),\n    MegaverseSpec(\"ObstaclesEasy\"),\n    MegaverseSpec(\"ObstaclesHard\"),\n    MegaverseSpec(\"Collect\"),\n    MegaverseSpec(\"Sokoban\"),\n    MegaverseSpec(\"HexMemory\"),\n    MegaverseSpec(\"HexExplore\"),\n    MegaverseSpec(\"Rearrange\"),\n\n    MegaverseSpec(\"multitask_Obstacles\"),\n    MegaverseSpec(\"multitask_megaverse8\"),\n]\n\n\nclass Wrapper(gym.Wrapper, RewardShapingInterface, TrainingInfoInterface):\n    \"\"\"Sets interface for PBT reward shaping, and also extra summaries for multi-task learning.\"\"\"\n\n    def __init__(self, env, increase_team_spirit, max_team_spirit_steps):\n        gym.Wrapper.__init__(self, env)\n        RewardShapingInterface.__init__(self)\n        TrainingInfoInterface.__init__(self)\n\n        self.num_agents = env.unwrapped.num_agents\n        self.is_multiagent = env.unwrapped.is_multiagent\n\n        self.episode_rewards = [0] * self.num_agents\n\n        self.increase_team_spirit = increase_team_spirit\n        self.max_team_spirit_steps = max_team_spirit_steps\n\n        self.approx_total_training_steps = 0\n\n    def get_default_reward_shaping(self):\n        return self.env.unwrapped.get_default_reward_shaping()\n\n    def get_current_reward_shaping(self, agent_idx: int):\n        return self.env.unwrapped.get_current_reward_shaping(agent_idx)\n\n    def set_reward_shaping(self, reward_shaping: dict, agent_idx: int):\n        return self.env.unwrapped.set_reward_shaping(reward_shaping, agent_idx)\n\n    def reset(self, **kwargs):\n        self.episode_rewards = [0] * self.num_agents\n        return self.env.reset(), {}\n\n    def step(self, action):\n        obs, rewards, dones, infos = self.env.step(action)\n\n        for i, info in enumerate(infos):\n            self.episode_rewards[i] += rewards[i]\n\n            if dones[i]:\n                if \"episode_extra_stats\" not in info:\n                    info[\"episode_extra_stats\"] = dict()\n                extra_stats = info[\"episode_extra_stats\"]\n                info[\"true_objective\"] = info[\"true_reward\"]\n                extra_stats[f\"z_{self.env.unwrapped.scenario_name.casefold()}_true_objective\"] = info[\"true_reward\"]\n                extra_stats[f\"z_{self.env.unwrapped.scenario_name.casefold()}_reward\"] = self.episode_rewards[i]\n\n                approx_total_training_steps = self.training_info.get(\"approx_total_training_steps\", 0)\n                extra_stats[\"z_approx_total_training_steps\"] = approx_total_training_steps\n\n                self.episode_rewards[i] = 0\n\n                if self.increase_team_spirit:\n                    rew_shaping = self.get_current_reward_shaping(i)\n                    rew_shaping[\"teamSpirit\"] = min(approx_total_training_steps / self.max_team_spirit_steps, 1.0)\n                    self.set_reward_shaping(rew_shaping, i)\n                    extra_stats[\"teamSpirit\"] = rew_shaping[\"teamSpirit\"]\n\n        terminated = dones\n        truncated = [False] * len(dones)\n        return obs, rewards, terminated, truncated, infos\n\n\ndef make_megaverse(env_name, cfg=None, env_config=None, render_mode: Optional[str] = None, **kwargs):\n    scenario_name = env_name.casefold()\n    log.debug(\"Using scenario %s\", scenario_name)\n\n    if \"multitask\" in scenario_name:\n        if env_config is not None and \"worker_index\" in env_config:\n            task_idx = env_config[\"worker_index\"]\n        else:\n            log.warning(\n                \"Could not find information about task id. Use task_id=0. (It is okay if this message appears once)\"\n            )\n            task_idx = 0\n\n        env = make_env_multitask(\n            scenario_name,\n            task_idx,\n            num_envs=cfg.megaverse_num_envs_per_instance,\n            num_agents_per_env=cfg.megaverse_num_agents_per_env,\n            num_simulation_threads=cfg.megaverse_num_simulation_threads,\n            use_vulkan=cfg.megaverse_use_vulkan,\n        )\n    else:\n        env = MegaverseEnv(\n            scenario_name=scenario_name,\n            num_envs=cfg.megaverse_num_envs_per_instance,\n            num_agents_per_env=cfg.megaverse_num_agents_per_env,\n            num_simulation_threads=cfg.megaverse_num_simulation_threads,\n            use_vulkan=cfg.megaverse_use_vulkan,\n        )\n\n    env = Wrapper(env, cfg.megaverse_increase_team_spirit, cfg.megaverse_max_team_spirit_steps)\n    return env\n"
  },
  {
    "path": "megaverse_rl/runs/__init__.py",
    "content": ""
  },
  {
    "path": "megaverse_rl/runs/megaverse_base_experiments.py",
    "content": "from sample_factory.launcher.run_description import Experiment, ParamGrid\n\n_params = ParamGrid([\n    ('env', ['TowerBuilding', 'ObstaclesEasy', 'ObstaclesHard', 'Collect', 'Sokoban', 'HexMemory', 'HexExplore', 'Rearrange']),\n    ('seed', [11111, 22222, 33333, 44444, 55555]),\n])\n\n_cli = 'python -m megaverse_rl.train_megaverse --train_for_seconds=360000000 --train_for_env_steps=2000000000 --algo=APPO --gamma=0.997 --use_rnn=True --rnn_num_layers=2 --num_workers=1 --num_envs_per_worker=2 --num_epochs=1 --rollout=32 --recurrence=32 --batch_size=2048 --actor_worker_gpus 0 --num_policies=1 --with_pbt=False --max_grad_norm=0.0 --exploration_loss=symmetric_kl --exploration_loss_coeff=0.001 --megaverse_num_simulation_threads=1 --megaverse_use_vulkan=True --policy_workers_per_policy=2 --reward_clip=30'\n\nEXPERIMENT_1AGENT = Experiment(\n    'megaverse_1ag',\n    _cli + ' --megaverse_num_envs_per_instance=36 --megaverse_num_agents_per_env=1',\n    _params.generate_params(randomize=False),\n)\n\nEXPERIMENT_2AGENTS = Experiment(\n    'megaverse_2ag',\n    _cli + ' --megaverse_num_envs_per_instance=18 --megaverse_num_agents_per_env=2',\n    _params.generate_params(randomize=False),\n)\n\nEXPERIMENT_4AGENTS = Experiment(\n    'megaverse_4ag',\n    _cli + ' --megaverse_num_envs_per_instance=9 --megaverse_num_agents_per_env=4',\n    _params.generate_params(randomize=False),\n)\n"
  },
  {
    "path": "megaverse_rl/runs/multi_agent.py",
    "content": "from sample_factory.launcher.run_description import RunDescription\n\nfrom megaverse_rl.runs.megaverse_base_experiments import EXPERIMENT_4AGENTS, EXPERIMENT_2AGENTS\n\nRUN_DESCRIPTION = RunDescription('megaverse_v115_multi_agent_v55', experiments=[EXPERIMENT_2AGENTS, EXPERIMENT_4AGENTS])\n"
  },
  {
    "path": "megaverse_rl/runs/multitask.py",
    "content": "from sample_factory.launcher.run_description import RunDescription, Experiment, ParamGrid\n\n_params = ParamGrid([\n    ('env', ['multitask_megaverse8']),\n    ('seed', [11111, 22222, 33333, 44444, 55555]),\n])\n\n_cli = 'python -m megaverse_rl.train_megaverse --train_for_seconds=360000000 --train_for_env_steps=2000000000 --algo=APPO --gamma=0.997 --use_rnn=True --rnn_num_layers=2 --num_workers=12 --num_envs_per_worker=2 --num_epochs=1 --rollout=32 --recurrence=32 --batch_size=2048 --actor_worker_gpus 0 --num_policies=1 --with_pbt=False --max_grad_norm=0.0 --exploration_loss=symmetric_kl --exploration_loss_coeff=0.001 --megaverse_num_simulation_threads=1 --megaverse_use_vulkan=True --policy_workers_per_policy=2 --reward_clip=30 --pbt_mix_policies_in_one_env=False'\n\nEXPERIMENT_1AGENT = Experiment(\n    'megaverse_multitask_obs',\n    _cli + ' --megaverse_num_envs_per_instance=36 --megaverse_num_agents_per_env=1',\n    _params.generate_params(randomize=False),\n)\n\nRUN_DESCRIPTION = RunDescription('megaverse_v115_multitask8_v55', experiments=[EXPERIMENT_1AGENT])\n"
  },
  {
    "path": "megaverse_rl/runs/multitask_obstacles.py",
    "content": "from sample_factory.launcher.run_description import RunDescription, Experiment, ParamGrid\n\n_params = ParamGrid([\n    ('env', ['multitask_Obstacles']),\n    ('seed', [11111, 22222, 33333, 44444, 55555]),\n])\n\n_cli = 'python -m megaverse_rl.train_megaverse --train_for_seconds=360000000 --train_for_env_steps=10000000000 --algo=APPO --gamma=0.997 --use_rnn=True --rnn_num_layers=2 --num_workers=12 --num_envs_per_worker=2 --num_epochs=1 --rollout=32 --recurrence=32 --batch_size=2048 --actor_worker_gpus 0 --num_policies=1 --with_pbt=False --max_grad_norm=0.0 --exploration_loss=symmetric_kl --exploration_loss_coeff=0.001 --megaverse_num_simulation_threads=1 --megaverse_use_vulkan=True --policy_workers_per_policy=2 --learner_main_loop_num_cores=2 --reward_clip=30 --pbt_mix_policies_in_one_env=False'\n\nEXPERIMENT_1AGENT = Experiment(\n    'megaverse_multitask_obs',\n    _cli + ' --megaverse_num_envs_per_instance=36 --megaverse_num_agents_per_env=1',\n    _params.generate_params(randomize=False),\n)\n\nRUN_DESCRIPTION = RunDescription('megaverse_v115_multitask_obstacles_v55', experiments=[EXPERIMENT_1AGENT])\n"
  },
  {
    "path": "megaverse_rl/runs/performance_benchmark.py",
    "content": "from sample_factory.launcher.run_description import RunDescription, Experiment, ParamGrid\n\nNUM_WORKERS = 20  # typically num logical cores\nNUM_WORKERS_MEGAVERSE = 10  # typically num logical cores / 2, limited by the num of available Vulkan contexts\nTIMEOUT_SECONDS = 180\nSAMPLER_GPUS = '0'  # replace with '0 1 2 3 4 5 6 7' for 8-GPU server\n\n_basic_cli = f'python -m sample_factory.run_algorithm --algo=DUMMY_SAMPLER --num_workers={NUM_WORKERS} --num_envs_per_worker=1 --experiment=benchmark --timeout_seconds={TIMEOUT_SECONDS}'\n\n_params_basic_envs = ParamGrid([\n    ('env', ['doom_benchmark', 'atari_breakout', 'dmlab_benchmark']),\n])\n\n_experiment_basic_envs = Experiment(\n    'benchmark_basic_envs',\n    _basic_cli,\n    _params_basic_envs.generate_params(randomize=False),\n)\n\n\n_megaverse_cli = f'python -m sample_factory.run_algorithm --algo=DUMMY_SAMPLER --num_workers={NUM_WORKERS_MEGAVERSE} --num_envs_per_worker=1 --experiment=benchmark --sampler_worker_gpus {SAMPLER_GPUS} --megaverse_num_envs_per_instance=64 --megaverse_num_agents_per_env=2 --megaverse_num_simulation_threads=2 --timeout_seconds={TIMEOUT_SECONDS}'\n\n_params_megaverse = ParamGrid([\n    ('env', ['obstacleshard']),\n    ('megaverse_use_vulkan', [True, False]),\n])\n\n_experiment_megaverse = Experiment(\n    'benchmark_megaverse',\n    _megaverse_cli,\n    _params_megaverse.generate_params(randomize=False),\n)\n\n\nRUN_DESCRIPTION = RunDescription('megaverse_bench_sampling', experiments=[_experiment_basic_envs, _experiment_megaverse])\n"
  },
  {
    "path": "megaverse_rl/runs/performance_benchmark_all_envs.py",
    "content": "from sample_factory.launcher.run_description import RunDescription, Experiment, ParamGrid\n\nNUM_WORKERS_MEGAVERSE = 48  # typically num logical cores / 2, limited by the num of available Vulkan contexts\nTIMEOUT_SECONDS = 180\nSAMPLER_GPUS = '0 1 2 3 4 5 6 7'  # replace with '0 1 2 3 4 5 6 7' for 8-GPU server\n\n_megaverse_cli = f'python -m sample_factory.run_algorithm --algo=DUMMY_SAMPLER --num_workers={NUM_WORKERS_MEGAVERSE} --num_envs_per_worker=1 --experiment=benchmark --sampler_worker_gpus {SAMPLER_GPUS} --megaverse_num_envs_per_instance=64 --megaverse_num_agents_per_env=2 --megaverse_num_simulation_threads=2 --timeout_seconds={TIMEOUT_SECONDS}'\n\n_params_megaverse = ParamGrid([\n    ('env', ['TowerBuilding', 'ObstaclesEasy', 'ObstaclesHard', 'Collect', 'Sokoban', 'HexMemory', 'HexExplore', 'Rearrange']),\n    ('megaverse_use_vulkan', [True]),\n])\n\n_experiment_megaverse = Experiment(\n    'benchmark_megaverse_8',\n    _megaverse_cli,\n    _params_megaverse.generate_params(randomize=False),\n)\n\n\nRUN_DESCRIPTION = RunDescription('megaverse_bench_sampling_all_envs', experiments=[_experiment_megaverse])\n"
  },
  {
    "path": "megaverse_rl/runs/single_agent.py",
    "content": "from sample_factory.launcher.run_description import RunDescription\n\nfrom megaverse_rl.runs.megaverse_base_experiments import EXPERIMENT_1AGENT\n\nRUN_DESCRIPTION = RunDescription('megaverse_arxiv', experiments=[EXPERIMENT_1AGENT])\n"
  },
  {
    "path": "megaverse_rl/runs/training_benchmark.py",
    "content": "from sample_factory.launcher.run_description import RunDescription, Experiment, ParamGrid\n\nNUM_WORKERS = 20  # typically num logical cores\nNUM_WORKERS_MEGAVERSE = 10  # typically num logical cores / 2, limited by the num of available Vulkan contexts\nTIMEOUT_SECONDS = 180\nACTOR_GPUS = '0'  # replace with '0 1 2 3 4 5 6 7' for 8-GPU server\nNUM_POLICIES = 1\n\n_basic_cli = f'python -m megaverse_rl.train_megaverse --train_for_seconds={TIMEOUT_SECONDS} --train_for_env_steps=20000000000 --algo=APPO --gamma=0.997 --use_rnn=True --rnn_num_layers=2 --num_workers={NUM_WORKERS} --num_envs_per_worker=16 --num_epochs=1 --rollout=32 --recurrence=32 --batch_size=2048 --num_policies={NUM_POLICIES} --with_pbt=False --max_grad_norm=0.0 --exploration_loss=symmetric_kl --exploration_loss_coeff=0.001 --policy_workers_per_policy=2 --learner_main_loop_num_cores=4 --reward_clip=30'\n\n_params_basic_envs = ParamGrid([\n    ('env', ['doom_benchmark', 'atari_breakout', 'dmlab_benchmark']),\n])\n\n_experiment_basic_envs = Experiment(\n    'benchmark_basic_envs',\n    _basic_cli,\n    _params_basic_envs.generate_params(randomize=False),\n)\n\n_megaverse_cli = f'python -m megaverse_rl.train_megaverse --train_for_seconds={TIMEOUT_SECONDS} --train_for_env_steps=20000000000 --algo=APPO --gamma=0.997 --use_rnn=True --rnn_num_layers=2 --num_workers={NUM_WORKERS_MEGAVERSE} --num_envs_per_worker=2 --num_epochs=1 --rollout=32 --recurrence=32 --batch_size=2048 --actor_worker_gpus {ACTOR_GPUS} --num_policies={NUM_POLICIES} --with_pbt=False --max_grad_norm=0.0 --exploration_loss=symmetric_kl --exploration_loss_coeff=0.001 --megaverse_num_simulation_threads=2 --megaverse_use_vulkan=True --policy_workers_per_policy=2 --learner_main_loop_num_cores=4 --reward_clip=30 --megaverse_num_envs_per_instance=36 --megaverse_num_agents_per_env=1 --pbt_mix_policies_in_one_env=False'\n_params_megaverse = ParamGrid([\n    ('env', ['megaverse_obstacleshard']),\n    ('megaverse_use_vulkan', [True, False]),\n])\n\n_experiment_megaverse = Experiment(\n    'benchmark_megaverse',\n    _megaverse_cli,\n    _params_megaverse.generate_params(randomize=False),\n)\n\n\nRUN_DESCRIPTION = RunDescription('megaverse_train_benchmark', experiments=[_experiment_basic_envs, _experiment_megaverse])\n"
  },
  {
    "path": "megaverse_rl/sampling_benchmark.py",
    "content": "\"\"\"\nMeasure pure sampling throughput.\n\n\"\"\"\n\nimport sys\n\nfrom sample_factory.algorithms.utils.arguments import arg_parser, postprocess_args\nfrom sample_factory.run_algorithm import run_algorithm\nfrom sample_factory.utils.get_available_gpus import get_gpus_without_triggering_pytorch_cuda_initialization\nfrom sample_factory.utils.utils import log\n\nfrom megaverse_rl.megaverse_utils import register_env\n\n\ndef main():\n    \"\"\"Script entry point.\"\"\"\n    gpus = get_gpus_without_triggering_pytorch_cuda_initialization()\n    gpus = gpus.strip().split(',')\n    gpus = [int(g) for g in gpus]\n\n    if len(gpus) <= 0:\n        log.error('Sampling benchmark requires at least one GPU')\n    else:\n        log.debug('Have %d GPUs (%r)', len(gpus), gpus)\n\n    register_env()\n\n    argv = sys.argv[1:]\n    argv.append('--algo=DUMMY_SAMPLER')\n\n    parser = arg_parser(argv)\n    parser.set_defaults(\n        sampler_worker_gpus=gpus,\n        num_workers=len(gpus) * 10,\n        megaverse_num_envs_per_instance=32,\n        megaverse_num_agents_per_env=4,\n        megaverse_num_simulation_threads=2,\n    )\n\n    # parse all the arguments (algo, env, and optionally evaluation)\n    cfg = parser.parse_args(argv)\n    cfg = postprocess_args(cfg, argv, parser)\n\n    status = run_algorithm(cfg)\n    return status\n\n\nif __name__ == '__main__':\n    sys.exit(main())\n"
  },
  {
    "path": "megaverse_rl/slurm/sbatch_template.sh",
    "content": "#!/bin/bash\nsource /homes/petrenko/miniconda3/etc/profile.d/conda.sh\nconda activate megaverse\ncd ~/megaverse\n"
  },
  {
    "path": "megaverse_rl/slurm/slurm_cli.txt",
    "content": "python -m sample_factory.launcher.run --run=megaverse_rl.runs.single_agent --runner=slurm --slurm_workdir=./megaverse_single_agent --experiment_suffix=slurm --pause_between=1 --slurm_gpus_per_job=1 --slurm_cpus_per_gpu=12 --slurm_sbatch_template=./megaverse_rl/slurm/sbatch_template.sh --slurm_print_only=False"
  },
  {
    "path": "megaverse_rl/tests/__init__.py",
    "content": ""
  },
  {
    "path": "megaverse_rl/tests/test_megaverse_env.py",
    "content": "from unittest import TestCase\n\nfrom sample_factory.envs.create_env import create_env\nfrom sample_factory.utils.utils import log\n\nfrom megaverse_rl.train_megaverse import register_megaverse_components, parse_megaverse_args\n\n\nclass TestMegaverse(TestCase):\n    def test_megaverse(self):\n        register_megaverse_components()\n\n        cfg = parse_megaverse_args(['--algo=APPO', '--env=Sokoban', '--experiment=test_megaverse'])\n\n        env = create_env(cfg.env, cfg=cfg)\n        log.info('Env action space: %r', env.action_space)\n        log.info('Env obs space: %r', env.observation_space)\n\n        env.reset()\n        total_rew = 0\n        for i in range(1000):\n            obs, rew, terminated, truncated, info = env.step([env.action_space.sample() for _ in range(env.num_agents)])\n            total_rew += sum(rew)\n\n        log.info('Total rew: %.3f', total_rew)\n"
  },
  {
    "path": "megaverse_rl/train_megaverse.py",
    "content": "\"\"\"\nMain script for training agents with SampleFactory.\n\n\"\"\"\n\nimport sys\n\nfrom sample_factory.cfg.arguments import parse_full_cfg, parse_sf_args\nfrom sample_factory.envs.env_utils import register_env\nfrom sample_factory.train import run_rl\nfrom megaverse_rl.megaverse_params import add_megaverse_args, megaverse_override_defaults\nfrom megaverse_rl.megaverse_utils import MEGAVERSE_ENVS, make_megaverse\n\n\ndef register_megaverse_envs():\n    for env in MEGAVERSE_ENVS:\n        register_env(env.name, make_megaverse)\n\n\ndef register_megaverse_components():\n    register_megaverse_envs()\n\n\ndef parse_megaverse_args(argv=None, evaluation=False):\n    parser, partial_cfg = parse_sf_args(argv=argv, evaluation=evaluation)\n    add_megaverse_args(partial_cfg.env, parser)\n    megaverse_override_defaults(partial_cfg.env, parser)\n    final_cfg = parse_full_cfg(parser, argv)\n    return final_cfg\n\n\ndef main():\n    \"\"\"Script entry point.\"\"\"\n    register_megaverse_components()\n    cfg = parse_megaverse_args()\n\n    status = run_rl(cfg)\n    return status\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n"
  },
  {
    "path": "setup.cfg",
    "content": "[build_ext]\nbuild_temp=build\n"
  },
  {
    "path": "setup.py",
    "content": "import os\nimport sys\nimport multiprocessing\nimport subprocess\nfrom os.path import join as pjoin\n\nfrom setuptools import setup, Extension, find_packages\nfrom setuptools.command.build_ext import build_ext\n\nsupported_platforms = [\"Linux\", \"Mac OS-X\"]\n\ndef find_in_path(name, path):\n    \"\"\"Find a file in a search path\"\"\"\n\n    # Adapted fom http://code.activestate.com/recipes/52224\n    for dir in path.split(os.pathsep):\n        binpath = pjoin(dir, name)\n        if os.path.exists(binpath):\n            return os.path.abspath(binpath)\n    return None\n\ndef locate_cuda():\n    \"\"\"Locate the CUDA environment on the system\n    Starts by looking for the CUDAHOME env variable. If not found,\n    everything is based on finding 'nvcc' in the PATH.\n    \"\"\"\n\n    # First check if the CUDAHOME env variable is in use\n    if 'CUDAHOME' in os.environ:\n        home = os.environ['CUDAHOME']\n        nvcc = pjoin(home, 'bin', 'nvcc')\n    else:\n        # Otherwise, search the PATH for NVCC\n        nvcc = find_in_path('nvcc', os.environ['PATH'])\n        if nvcc is None:\n            raise EnvironmentError('The nvcc binary could not be '\n                'located in your $PATH. Either add it to your path, '\n                'or set $CUDAHOME')\n\n    return nvcc\n\nclass CMakeExtension(Extension):\n    def __init__(self, name, sourcedir=''):\n        Extension.__init__(self, name, sources=[])\n        self.sourcedir = os.path.abspath(sourcedir)\n\n\nclass CMakeBuild(build_ext):\n    def run(self):\n        try:\n            subprocess.check_output(['cmake', '--version'])\n        except OSError:\n            raise RuntimeError(\n                'CMake must be installed to build the following extensions: ' +\n                ', '.join(e.name for e in self.extensions),\n            )\n\n        for ext in self.extensions:\n            self.build_extension(ext)\n\n    def build_extension(self, ext):\n        extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))\n        # required for auto-detection of auxiliary \"native\" libs\n        if not extdir.endswith(os.path.sep):\n            extdir += os.path.sep\n\n        cmake_args = [\n            f'-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}',\n            f'-DPYTHON_EXECUTABLE={sys.executable}',\n            # f'-DOpenCV_DIR =/home/alex/all/lib/opencv/build',  # TODO!!!\n        ]\n\n        if sys.platform != \"darwin\":\n            # if not on mac, look for cuda/nvcc\n            cmake_args.append(f'-DCMAKE_CUDA_COMPILER={locate_cuda()}')\n\n        # that's a hacky way to do it but the best idea I have at the moment\n        bullet_root = os.environ.get('BULLET_ROOT', None)\n        if bullet_root is not None:\n            cmake_args.append(f'-DBULLET_ROOT={bullet_root}')\n\n        cfg = 'Debug' if self.debug else 'Release'\n        build_args = ['--config', cfg]\n\n        if os.environ.get('MEGAVERSE_WITH_GUI') == '1':\n            build_gui = 'ON'\n        else:\n            build_gui = 'OFF'\n\n        cmake_args += [f'-DCMAKE_BUILD_TYPE={cfg}', f'-DBUILD_GUI_APPS={build_gui}']\n        build_args += ['--', f'-j{multiprocessing.cpu_count()}']\n\n        env = os.environ.copy()\n\n        if not os.path.exists(self.build_temp):\n            os.makedirs(self.build_temp)\n\n        print('Build temp directory is ', self.build_temp)\n\n        cmake_cmd = ['cmake', ext.sourcedir] + cmake_args\n        print(f'CMake command is: {\" \".join(cmake_cmd)}')\n\n        subprocess.check_call(cmake_cmd, cwd=self.build_temp, env=env)\n        subprocess.check_call(\n            ['cmake', '--build', '.', '--target', 'megaverse'] + build_args, cwd=self.build_temp,\n        )\n\n        print('Completed the build!')\n\n\ndef main():\n    setup(\n        name='megaverse',\n        version='0.0.2',\n        author='Aleksei Petrenko',\n        author_email='apetrenko1991@gmail.com',\n        description='Fast immersive environment',\n        long_description='',\n        platforms=supported_platforms,\n        packages=find_packages(exclude=['test', 'benchmarks']),\n        include_package_data=True,\n        ext_modules=[CMakeExtension('megaverse.extension.megaverse', 'src')],\n        cmdclass=dict(build_ext=CMakeBuild),\n        zip_safe=False,\n        install_requires=[\n            'gym>=0.17.1',\n        ],\n    )\n\n    return 0\n\n\nif __name__ == '__main__':\n    sys.exit(main())\n"
  },
  {
    "path": "src/3rdparty/CMakeLists.txt",
    "content": "if (NOT APPLE)\n    add_subdirectory(v4r EXCLUDE_FROM_ALL)\nendif ()\n\nadd_subdirectory(corrade EXCLUDE_FROM_ALL)\nfind_package(Corrade REQUIRED Main)\n\nif (BUILD_GUI_APPS)\n    set(WITH_SDL2APPLICATION ON CACHE BOOL \"\" FORCE)\nelse()\n    message(STATUS \"Build without GUI apps!\")\nendif()\n\nif (NOT CORRADE_TARGET_APPLE)\n    set(WITH_WINDOWLESSEGLAPPLICATION ON CACHE BOOL \"\" FORCE)\nelse ()\n    set(WITH_WINDOWLESSCGLAPPLICATION ON CACHE BOOL \"WITH_WINDOWLESSCGLAPPLICATION\" FORCE)\nendif ()\nset(WITH_TGAIMPORTER ON CACHE BOOL \"\" FORCE)\nadd_subdirectory(magnum EXCLUDE_FROM_ALL)\n\n#find_package(Bullet REQUIRED)\n\nset(WITH_BULLET ON CACHE BOOL \"\" FORCE)\nadd_subdirectory(magnum-integration EXCLUDE_FROM_ALL)\n\nfind_package(Magnum REQUIRED GL MeshTools Primitives SceneGraph Shaders Trade)\nif (BUILD_GUI_APPS)\n    find_package(Magnum REQUIRED Sdl2Application)\nendif()\nfind_package(MagnumIntegration REQUIRED Bullet)\n\nadd_subdirectory(googletest-1.10.0)\ninclude_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})\n\nif (NOT CORRADE_TARGET_APPLE)\n    add_subdirectory(glad)\nendif ()\n\nadd_subdirectory(pybind11)\n"
  },
  {
    "path": "src/3rdparty/glad/CMakeLists.txt",
    "content": "add_library_default(glad)\n"
  },
  {
    "path": "src/3rdparty/glad/include/KHR/khrplatform.h",
    "content": "#ifndef __khrplatform_h_\n#define __khrplatform_h_\n\n/*\n** Copyright (c) 2008-2018 The Khronos Group Inc.\n**\n** Permission is hereby granted, free of charge, to any person obtaining a\n** copy of this software and/or associated documentation files (the\n** \"Materials\"), to deal in the Materials without restriction, including\n** without limitation the rights to use, copy, modify, merge, publish,\n** distribute, sublicense, and/or sell copies of the Materials, and to\n** permit persons to whom the Materials are furnished to do so, subject to\n** the following conditions:\n**\n** The above copyright notice and this permission notice shall be included\n** in all copies or substantial portions of the Materials.\n**\n** THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.\n*/\n\n/* Khronos platform-specific types and definitions.\n *\n * The master copy of khrplatform.h is maintained in the Khronos EGL\n * Registry repository at https://github.com/KhronosGroup/EGL-Registry\n * The last semantic modification to khrplatform.h was at commit ID:\n *      67a3e0864c2d75ea5287b9f3d2eb74a745936692\n *\n * Adopters may modify this file to suit their platform. Adopters are\n * encouraged to submit platform specific modifications to the Khronos\n * group so that they can be included in future versions of this file.\n * Please submit changes by filing pull requests or issues on\n * the EGL Registry repository linked above.\n *\n *\n * See the Implementer's Guidelines for information about where this file\n * should be located on your system and for more details of its use:\n *    http://www.khronos.org/registry/implementers_guide.pdf\n *\n * This file should be included as\n *        #include <KHR/khrplatform.h>\n * by Khronos client API header files that use its types and defines.\n *\n * The types in khrplatform.h should only be used to define API-specific types.\n *\n * Types defined in khrplatform.h:\n *    khronos_int8_t              signed   8  bit\n *    khronos_uint8_t             unsigned 8  bit\n *    khronos_int16_t             signed   16 bit\n *    khronos_uint16_t            unsigned 16 bit\n *    khronos_int32_t             signed   32 bit\n *    khronos_uint32_t            unsigned 32 bit\n *    khronos_int64_t             signed   64 bit\n *    khronos_uint64_t            unsigned 64 bit\n *    khronos_intptr_t            signed   same number of bits as a pointer\n *    khronos_uintptr_t           unsigned same number of bits as a pointer\n *    khronos_ssize_t             signed   size\n *    khronos_usize_t             unsigned size\n *    khronos_float_t             signed   32 bit floating point\n *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds\n *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in\n *                                         nanoseconds\n *    khronos_stime_nanoseconds_t signed time interval in nanoseconds\n *    khronos_boolean_enum_t      enumerated boolean type. This should\n *      only be used as a base type when a client API's boolean type is\n *      an enum. Client APIs which use an integer or other type for\n *      booleans cannot use this as the base type for their boolean.\n *\n * Tokens defined in khrplatform.h:\n *\n *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.\n *\n *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.\n *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.\n *\n * Calling convention macros defined in this file:\n *    KHRONOS_APICALL\n *    KHRONOS_APIENTRY\n *    KHRONOS_APIATTRIBUTES\n *\n * These may be used in function prototypes as:\n *\n *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(\n *                                  int arg1,\n *                                  int arg2) KHRONOS_APIATTRIBUTES;\n */\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APICALL\n *-------------------------------------------------------------------------\n * This precedes the return type of the function in the function prototype.\n */\n#if defined(_WIN32) && !defined(__SCITECH_SNAP__)\n#   define KHRONOS_APICALL __declspec(dllimport)\n#elif defined (__SYMBIAN32__)\n#   define KHRONOS_APICALL IMPORT_C\n#elif defined(__ANDROID__)\n#   define KHRONOS_APICALL __attribute__((visibility(\"default\")))\n#else\n#   define KHRONOS_APICALL\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APIENTRY\n *-------------------------------------------------------------------------\n * This follows the return type of the function  and precedes the function\n * name in the function prototype.\n */\n#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)\n    /* Win32 but not WinCE */\n#   define KHRONOS_APIENTRY __stdcall\n#else\n#   define KHRONOS_APIENTRY\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APIATTRIBUTES\n *-------------------------------------------------------------------------\n * This follows the closing parenthesis of the function prototype arguments.\n */\n#if defined (__ARMCC_2__)\n#define KHRONOS_APIATTRIBUTES __softfp\n#else\n#define KHRONOS_APIATTRIBUTES\n#endif\n\n/*-------------------------------------------------------------------------\n * basic type definitions\n *-----------------------------------------------------------------------*/\n#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)\n\n\n/*\n * Using <stdint.h>\n */\n#include <stdint.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif defined(__VMS ) || defined(__sgi)\n\n/*\n * Using <inttypes.h>\n */\n#include <inttypes.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)\n\n/*\n * Win32\n */\ntypedef __int32                 khronos_int32_t;\ntypedef unsigned __int32        khronos_uint32_t;\ntypedef __int64                 khronos_int64_t;\ntypedef unsigned __int64        khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif defined(__sun__) || defined(__digital__)\n\n/*\n * Sun or Digital\n */\ntypedef int                     khronos_int32_t;\ntypedef unsigned int            khronos_uint32_t;\n#if defined(__arch64__) || defined(_LP64)\ntypedef long int                khronos_int64_t;\ntypedef unsigned long int       khronos_uint64_t;\n#else\ntypedef long long int           khronos_int64_t;\ntypedef unsigned long long int  khronos_uint64_t;\n#endif /* __arch64__ */\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif 0\n\n/*\n * Hypothetical platform with no float or int64 support\n */\ntypedef int                     khronos_int32_t;\ntypedef unsigned int            khronos_uint32_t;\n#define KHRONOS_SUPPORT_INT64   0\n#define KHRONOS_SUPPORT_FLOAT   0\n\n#else\n\n/*\n * Generic fallback\n */\n#include <stdint.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#endif\n\n\n/*\n * Types that are (so far) the same on all platforms\n */\ntypedef signed   char          khronos_int8_t;\ntypedef unsigned char          khronos_uint8_t;\ntypedef signed   short int     khronos_int16_t;\ntypedef unsigned short int     khronos_uint16_t;\n\n/*\n * Types that differ between LLP64 and LP64 architectures - in LLP64,\n * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears\n * to be the only LLP64 architecture in current use.\n */\n#ifdef _WIN64\ntypedef signed   long long int khronos_intptr_t;\ntypedef unsigned long long int khronos_uintptr_t;\ntypedef signed   long long int khronos_ssize_t;\ntypedef unsigned long long int khronos_usize_t;\n#else\ntypedef signed   long  int     khronos_intptr_t;\ntypedef unsigned long  int     khronos_uintptr_t;\ntypedef signed   long  int     khronos_ssize_t;\ntypedef unsigned long  int     khronos_usize_t;\n#endif\n\n#if KHRONOS_SUPPORT_FLOAT\n/*\n * Float type\n */\ntypedef          float         khronos_float_t;\n#endif\n\n#if KHRONOS_SUPPORT_INT64\n/* Time types\n *\n * These types can be used to represent a time interval in nanoseconds or\n * an absolute Unadjusted System Time.  Unadjusted System Time is the number\n * of nanoseconds since some arbitrary system event (e.g. since the last\n * time the system booted).  The Unadjusted System Time is an unsigned\n * 64 bit value that wraps back to 0 every 584 years.  Time intervals\n * may be either signed or unsigned.\n */\ntypedef khronos_uint64_t       khronos_utime_nanoseconds_t;\ntypedef khronos_int64_t        khronos_stime_nanoseconds_t;\n#endif\n\n/*\n * Dummy value used to pad enum types to 32 bits.\n */\n#ifndef KHRONOS_MAX_ENUM\n#define KHRONOS_MAX_ENUM 0x7FFFFFFF\n#endif\n\n/*\n * Enumerated boolean type\n *\n * Values other than zero should be considered to be true.  Therefore\n * comparisons should not be made against KHRONOS_TRUE.\n */\ntypedef enum {\n    KHRONOS_FALSE = 0,\n    KHRONOS_TRUE  = 1,\n    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM\n} khronos_boolean_enum_t;\n\n#endif /* __khrplatform_h_ */\n"
  },
  {
    "path": "src/3rdparty/glad/include/glad/glad_egl.h",
    "content": "/*\n\n    EGL loader generated by glad 0.1.25 on Mon Jan 14 16:56:21 2019.\n\n    Language/Generator: C/C++\n    Specification: egl\n    APIs: egl=1.5\n    Profile: -\n    Extensions:\n        EGL_ANDROID_blob_cache,\n        EGL_ANDROID_create_native_client_buffer,\n        EGL_ANDROID_framebuffer_target,\n        EGL_ANDROID_front_buffer_auto_refresh,\n        EGL_ANDROID_get_frame_timestamps,\n        EGL_ANDROID_get_native_client_buffer,\n        EGL_ANDROID_image_native_buffer,\n        EGL_ANDROID_native_fence_sync,\n        EGL_ANDROID_presentation_time,\n        EGL_ANDROID_recordable,\n        EGL_ANGLE_d3d_share_handle_client_buffer,\n        EGL_ANGLE_device_d3d,\n        EGL_ANGLE_query_surface_pointer,\n        EGL_ANGLE_surface_d3d_texture_2d_share_handle,\n        EGL_ANGLE_window_fixed_size,\n        EGL_ARM_implicit_external_sync,\n        EGL_ARM_pixmap_multisample_discard,\n        EGL_EXT_bind_to_front,\n        EGL_EXT_buffer_age,\n        EGL_EXT_client_extensions,\n        EGL_EXT_client_sync,\n        EGL_EXT_compositor,\n        EGL_EXT_create_context_robustness,\n        EGL_EXT_device_base,\n        EGL_EXT_device_drm,\n        EGL_EXT_device_enumeration,\n        EGL_EXT_device_openwf,\n        EGL_EXT_device_query,\n        EGL_EXT_gl_colorspace_bt2020_linear,\n        EGL_EXT_gl_colorspace_bt2020_pq,\n        EGL_EXT_gl_colorspace_display_p3,\n        EGL_EXT_gl_colorspace_display_p3_linear,\n        EGL_EXT_gl_colorspace_display_p3_passthrough,\n        EGL_EXT_gl_colorspace_scrgb,\n        EGL_EXT_gl_colorspace_scrgb_linear,\n        EGL_EXT_image_dma_buf_import,\n        EGL_EXT_image_dma_buf_import_modifiers,\n        EGL_EXT_image_gl_colorspace,\n        EGL_EXT_image_implicit_sync_control,\n        EGL_EXT_multiview_window,\n        EGL_EXT_output_base,\n        EGL_EXT_output_drm,\n        EGL_EXT_output_openwf,\n        EGL_EXT_pixel_format_float,\n        EGL_EXT_platform_base,\n        EGL_EXT_platform_device,\n        EGL_EXT_platform_wayland,\n        EGL_EXT_platform_x11,\n        EGL_EXT_protected_content,\n        EGL_EXT_protected_surface,\n        EGL_EXT_stream_consumer_egloutput,\n        EGL_EXT_surface_CTA861_3_metadata,\n        EGL_EXT_surface_SMPTE2086_metadata,\n        EGL_EXT_swap_buffers_with_damage,\n        EGL_EXT_sync_reuse,\n        EGL_EXT_yuv_surface,\n        EGL_HI_clientpixmap,\n        EGL_HI_colorformats,\n        EGL_IMG_context_priority,\n        EGL_IMG_image_plane_attribs,\n        EGL_KHR_cl_event,\n        EGL_KHR_cl_event2,\n        EGL_KHR_client_get_all_proc_addresses,\n        EGL_KHR_config_attribs,\n        EGL_KHR_context_flush_control,\n        EGL_KHR_create_context,\n        EGL_KHR_create_context_no_error,\n        EGL_KHR_debug,\n        EGL_KHR_display_reference,\n        EGL_KHR_fence_sync,\n        EGL_KHR_get_all_proc_addresses,\n        EGL_KHR_gl_colorspace,\n        EGL_KHR_gl_renderbuffer_image,\n        EGL_KHR_gl_texture_2D_image,\n        EGL_KHR_gl_texture_3D_image,\n        EGL_KHR_gl_texture_cubemap_image,\n        EGL_KHR_image,\n        EGL_KHR_image_base,\n        EGL_KHR_image_pixmap,\n        EGL_KHR_lock_surface,\n        EGL_KHR_lock_surface2,\n        EGL_KHR_lock_surface3,\n        EGL_KHR_mutable_render_buffer,\n        EGL_KHR_no_config_context,\n        EGL_KHR_partial_update,\n        EGL_KHR_platform_android,\n        EGL_KHR_platform_gbm,\n        EGL_KHR_platform_wayland,\n        EGL_KHR_platform_x11,\n        EGL_KHR_reusable_sync,\n        EGL_KHR_stream,\n        EGL_KHR_stream_attrib,\n        EGL_KHR_stream_consumer_gltexture,\n        EGL_KHR_stream_cross_process_fd,\n        EGL_KHR_stream_fifo,\n        EGL_KHR_stream_producer_aldatalocator,\n        EGL_KHR_stream_producer_eglsurface,\n        EGL_KHR_surfaceless_context,\n        EGL_KHR_swap_buffers_with_damage,\n        EGL_KHR_vg_parent_image,\n        EGL_KHR_wait_sync,\n        EGL_MESA_drm_image,\n        EGL_MESA_image_dma_buf_export,\n        EGL_MESA_platform_gbm,\n        EGL_MESA_platform_surfaceless,\n        EGL_NOK_swap_region,\n        EGL_NOK_swap_region2,\n        EGL_NOK_texture_from_pixmap,\n        EGL_NV_3dvision_surface,\n        EGL_NV_context_priority_realtime,\n        EGL_NV_coverage_sample,\n        EGL_NV_coverage_sample_resolve,\n        EGL_NV_cuda_event,\n        EGL_NV_depth_nonlinear,\n        EGL_NV_device_cuda,\n        EGL_NV_native_query,\n        EGL_NV_post_convert_rounding,\n        EGL_NV_post_sub_buffer,\n        EGL_NV_robustness_video_memory_purge,\n        EGL_NV_stream_consumer_gltexture_yuv,\n        EGL_NV_stream_cross_display,\n        EGL_NV_stream_cross_object,\n        EGL_NV_stream_cross_partition,\n        EGL_NV_stream_cross_process,\n        EGL_NV_stream_cross_system,\n        EGL_NV_stream_fifo_next,\n        EGL_NV_stream_fifo_synchronous,\n        EGL_NV_stream_flush,\n        EGL_NV_stream_frame_limits,\n        EGL_NV_stream_metadata,\n        EGL_NV_stream_remote,\n        EGL_NV_stream_reset,\n        EGL_NV_stream_socket,\n        EGL_NV_stream_socket_inet,\n        EGL_NV_stream_socket_unix,\n        EGL_NV_stream_sync,\n        EGL_NV_sync,\n        EGL_NV_system_time,\n        EGL_TIZEN_image_native_buffer,\n        EGL_TIZEN_image_native_surface\n    Loader: True\n    Local files: False\n    Omit khrplatform: False\n\n    Commandline:\n        --api=\"egl=1.5\" --generator=\"c\" --spec=\"egl\" --extensions=\"EGL_ANDROID_blob_cache,EGL_ANDROID_create_native_client_buffer,EGL_ANDROID_framebuffer_target,EGL_ANDROID_front_buffer_auto_refresh,EGL_ANDROID_get_frame_timestamps,EGL_ANDROID_get_native_client_buffer,EGL_ANDROID_image_native_buffer,EGL_ANDROID_native_fence_sync,EGL_ANDROID_presentation_time,EGL_ANDROID_recordable,EGL_ANGLE_d3d_share_handle_client_buffer,EGL_ANGLE_device_d3d,EGL_ANGLE_query_surface_pointer,EGL_ANGLE_surface_d3d_texture_2d_share_handle,EGL_ANGLE_window_fixed_size,EGL_ARM_implicit_external_sync,EGL_ARM_pixmap_multisample_discard,EGL_EXT_bind_to_front,EGL_EXT_buffer_age,EGL_EXT_client_extensions,EGL_EXT_client_sync,EGL_EXT_compositor,EGL_EXT_create_context_robustness,EGL_EXT_device_base,EGL_EXT_device_drm,EGL_EXT_device_enumeration,EGL_EXT_device_openwf,EGL_EXT_device_query,EGL_EXT_gl_colorspace_bt2020_linear,EGL_EXT_gl_colorspace_bt2020_pq,EGL_EXT_gl_colorspace_display_p3,EGL_EXT_gl_colorspace_display_p3_linear,EGL_EXT_gl_colorspace_display_p3_passthrough,EGL_EXT_gl_colorspace_scrgb,EGL_EXT_gl_colorspace_scrgb_linear,EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_EXT_image_gl_colorspace,EGL_EXT_image_implicit_sync_control,EGL_EXT_multiview_window,EGL_EXT_output_base,EGL_EXT_output_drm,EGL_EXT_output_openwf,EGL_EXT_pixel_format_float,EGL_EXT_platform_base,EGL_EXT_platform_device,EGL_EXT_platform_wayland,EGL_EXT_platform_x11,EGL_EXT_protected_content,EGL_EXT_protected_surface,EGL_EXT_stream_consumer_egloutput,EGL_EXT_surface_CTA861_3_metadata,EGL_EXT_surface_SMPTE2086_metadata,EGL_EXT_swap_buffers_with_damage,EGL_EXT_sync_reuse,EGL_EXT_yuv_surface,EGL_HI_clientpixmap,EGL_HI_colorformats,EGL_IMG_context_priority,EGL_IMG_image_plane_attribs,EGL_KHR_cl_event,EGL_KHR_cl_event2,EGL_KHR_client_get_all_proc_addresses,EGL_KHR_config_attribs,EGL_KHR_context_flush_control,EGL_KHR_create_context,EGL_KHR_create_context_no_error,EGL_KHR_debug,EGL_KHR_display_reference,EGL_KHR_fence_sync,EGL_KHR_get_all_proc_addresses,EGL_KHR_gl_colorspace,EGL_KHR_gl_renderbuffer_image,EGL_KHR_gl_texture_2D_image,EGL_KHR_gl_texture_3D_image,EGL_KHR_gl_texture_cubemap_image,EGL_KHR_image,EGL_KHR_image_base,EGL_KHR_image_pixmap,EGL_KHR_lock_surface,EGL_KHR_lock_surface2,EGL_KHR_lock_surface3,EGL_KHR_mutable_render_buffer,EGL_KHR_no_config_context,EGL_KHR_partial_update,EGL_KHR_platform_android,EGL_KHR_platform_gbm,EGL_KHR_platform_wayland,EGL_KHR_platform_x11,EGL_KHR_reusable_sync,EGL_KHR_stream,EGL_KHR_stream_attrib,EGL_KHR_stream_consumer_gltexture,EGL_KHR_stream_cross_process_fd,EGL_KHR_stream_fifo,EGL_KHR_stream_producer_aldatalocator,EGL_KHR_stream_producer_eglsurface,EGL_KHR_surfaceless_context,EGL_KHR_swap_buffers_with_damage,EGL_KHR_vg_parent_image,EGL_KHR_wait_sync,EGL_MESA_drm_image,EGL_MESA_image_dma_buf_export,EGL_MESA_platform_gbm,EGL_MESA_platform_surfaceless,EGL_NOK_swap_region,EGL_NOK_swap_region2,EGL_NOK_texture_from_pixmap,EGL_NV_3dvision_surface,EGL_NV_context_priority_realtime,EGL_NV_coverage_sample,EGL_NV_coverage_sample_resolve,EGL_NV_cuda_event,EGL_NV_depth_nonlinear,EGL_NV_device_cuda,EGL_NV_native_query,EGL_NV_post_convert_rounding,EGL_NV_post_sub_buffer,EGL_NV_robustness_video_memory_purge,EGL_NV_stream_consumer_gltexture_yuv,EGL_NV_stream_cross_display,EGL_NV_stream_cross_object,EGL_NV_stream_cross_partition,EGL_NV_stream_cross_process,EGL_NV_stream_cross_system,EGL_NV_stream_fifo_next,EGL_NV_stream_fifo_synchronous,EGL_NV_stream_flush,EGL_NV_stream_frame_limits,EGL_NV_stream_metadata,EGL_NV_stream_remote,EGL_NV_stream_reset,EGL_NV_stream_socket,EGL_NV_stream_socket_inet,EGL_NV_stream_socket_unix,EGL_NV_stream_sync,EGL_NV_sync,EGL_NV_system_time,EGL_TIZEN_image_native_buffer,EGL_TIZEN_image_native_surface\"\n    Online:\n        Too many extensions\n*/\n\n\n#ifndef __glad_egl_h_\n\n#ifdef __egl_h_\n#error EGL header already included, remove this include, glad already provides it\n#endif\n\n#define __glad_egl_h_\n#define __egl_h_\n\n#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN 1\n#endif\n#ifndef NOMINMAX\n#define NOMINMAX 1\n#endif\n#include <windows.h>\n#endif\n\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\n#ifndef GLAPI\n#define GLAPI extern\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef void* (* GLADloadproc)(const char *name);\n\nGLAPI int gladLoadEGL(void);\nGLAPI int gladLoadEGLLoader(GLADloadproc);\n\n#include <KHR/khrplatform.h>\n#include <EGL/eglplatform.h>\nstruct AHardwareBuffer;\ntypedef unsigned int EGLBoolean;\ntypedef unsigned int EGLenum;\ntypedef intptr_t EGLAttribKHR;\ntypedef intptr_t EGLAttrib;\ntypedef void *EGLClientBuffer;\ntypedef void *EGLConfig;\ntypedef void *EGLContext;\ntypedef void *EGLDeviceEXT;\ntypedef void *EGLDisplay;\ntypedef void *EGLImage;\ntypedef void *EGLImageKHR;\ntypedef void *EGLLabelKHR;\ntypedef void *EGLObjectKHR;\ntypedef void *EGLOutputLayerEXT;\ntypedef void *EGLOutputPortEXT;\ntypedef void *EGLStreamKHR;\ntypedef void *EGLSurface;\ntypedef void *EGLSync;\ntypedef void *EGLSyncKHR;\ntypedef void *EGLSyncNV;\ntypedef void (*__eglMustCastToProperFunctionPointerType)(void);\ntypedef khronos_utime_nanoseconds_t EGLTimeKHR;\ntypedef khronos_utime_nanoseconds_t EGLTime;\ntypedef khronos_utime_nanoseconds_t EGLTimeNV;\ntypedef khronos_utime_nanoseconds_t EGLuint64NV;\ntypedef khronos_uint64_t EGLuint64KHR;\ntypedef khronos_stime_nanoseconds_t EGLnsecsANDROID;\ntypedef int EGLNativeFileDescriptorKHR;\ntypedef khronos_ssize_t EGLsizeiANDROID;\ntypedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);\ntypedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);\nstruct EGLClientPixmapHI {\n    void  *pData;\n    EGLint iWidth;\n    EGLint iHeight;\n    EGLint iStride;\n};\ntypedef void (APIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);\n#define EGL_ALPHA_SIZE 0x3021\n#define EGL_BAD_ACCESS 0x3002\n#define EGL_BAD_ALLOC 0x3003\n#define EGL_BAD_ATTRIBUTE 0x3004\n#define EGL_BAD_CONFIG 0x3005\n#define EGL_BAD_CONTEXT 0x3006\n#define EGL_BAD_CURRENT_SURFACE 0x3007\n#define EGL_BAD_DISPLAY 0x3008\n#define EGL_BAD_MATCH 0x3009\n#define EGL_BAD_NATIVE_PIXMAP 0x300A\n#define EGL_BAD_NATIVE_WINDOW 0x300B\n#define EGL_BAD_PARAMETER 0x300C\n#define EGL_BAD_SURFACE 0x300D\n#define EGL_BLUE_SIZE 0x3022\n#define EGL_BUFFER_SIZE 0x3020\n#define EGL_CONFIG_CAVEAT 0x3027\n#define EGL_CONFIG_ID 0x3028\n#define EGL_CORE_NATIVE_ENGINE 0x305B\n#define EGL_DEPTH_SIZE 0x3025\n#define EGL_DONT_CARE EGL_CAST(EGLint,-1)\n#define EGL_DRAW 0x3059\n#define EGL_EXTENSIONS 0x3055\n#define EGL_FALSE 0\n#define EGL_GREEN_SIZE 0x3023\n#define EGL_HEIGHT 0x3056\n#define EGL_LARGEST_PBUFFER 0x3058\n#define EGL_LEVEL 0x3029\n#define EGL_MAX_PBUFFER_HEIGHT 0x302A\n#define EGL_MAX_PBUFFER_PIXELS 0x302B\n#define EGL_MAX_PBUFFER_WIDTH 0x302C\n#define EGL_NATIVE_RENDERABLE 0x302D\n#define EGL_NATIVE_VISUAL_ID 0x302E\n#define EGL_NATIVE_VISUAL_TYPE 0x302F\n#define EGL_NONE 0x3038\n#define EGL_NON_CONFORMANT_CONFIG 0x3051\n#define EGL_NOT_INITIALIZED 0x3001\n#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)\n#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)\n#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)\n#define EGL_PBUFFER_BIT 0x0001\n#define EGL_PIXMAP_BIT 0x0002\n#define EGL_READ 0x305A\n#define EGL_RED_SIZE 0x3024\n#define EGL_SAMPLES 0x3031\n#define EGL_SAMPLE_BUFFERS 0x3032\n#define EGL_SLOW_CONFIG 0x3050\n#define EGL_STENCIL_SIZE 0x3026\n#define EGL_SUCCESS 0x3000\n#define EGL_SURFACE_TYPE 0x3033\n#define EGL_TRANSPARENT_BLUE_VALUE 0x3035\n#define EGL_TRANSPARENT_GREEN_VALUE 0x3036\n#define EGL_TRANSPARENT_RED_VALUE 0x3037\n#define EGL_TRANSPARENT_RGB 0x3052\n#define EGL_TRANSPARENT_TYPE 0x3034\n#define EGL_TRUE 1\n#define EGL_VENDOR 0x3053\n#define EGL_VERSION 0x3054\n#define EGL_WIDTH 0x3057\n#define EGL_WINDOW_BIT 0x0004\n#define EGL_BACK_BUFFER 0x3084\n#define EGL_BIND_TO_TEXTURE_RGB 0x3039\n#define EGL_BIND_TO_TEXTURE_RGBA 0x303A\n#define EGL_CONTEXT_LOST 0x300E\n#define EGL_MIN_SWAP_INTERVAL 0x303B\n#define EGL_MAX_SWAP_INTERVAL 0x303C\n#define EGL_MIPMAP_TEXTURE 0x3082\n#define EGL_MIPMAP_LEVEL 0x3083\n#define EGL_NO_TEXTURE 0x305C\n#define EGL_TEXTURE_2D 0x305F\n#define EGL_TEXTURE_FORMAT 0x3080\n#define EGL_TEXTURE_RGB 0x305D\n#define EGL_TEXTURE_RGBA 0x305E\n#define EGL_TEXTURE_TARGET 0x3081\n#define EGL_ALPHA_FORMAT 0x3088\n#define EGL_ALPHA_FORMAT_NONPRE 0x308B\n#define EGL_ALPHA_FORMAT_PRE 0x308C\n#define EGL_ALPHA_MASK_SIZE 0x303E\n#define EGL_BUFFER_PRESERVED 0x3094\n#define EGL_BUFFER_DESTROYED 0x3095\n#define EGL_CLIENT_APIS 0x308D\n#define EGL_COLORSPACE 0x3087\n#define EGL_COLORSPACE_sRGB 0x3089\n#define EGL_COLORSPACE_LINEAR 0x308A\n#define EGL_COLOR_BUFFER_TYPE 0x303F\n#define EGL_CONTEXT_CLIENT_TYPE 0x3097\n#define EGL_DISPLAY_SCALING 10000\n#define EGL_HORIZONTAL_RESOLUTION 0x3090\n#define EGL_LUMINANCE_BUFFER 0x308F\n#define EGL_LUMINANCE_SIZE 0x303D\n#define EGL_OPENGL_ES_BIT 0x0001\n#define EGL_OPENVG_BIT 0x0002\n#define EGL_OPENGL_ES_API 0x30A0\n#define EGL_OPENVG_API 0x30A1\n#define EGL_OPENVG_IMAGE 0x3096\n#define EGL_PIXEL_ASPECT_RATIO 0x3092\n#define EGL_RENDERABLE_TYPE 0x3040\n#define EGL_RENDER_BUFFER 0x3086\n#define EGL_RGB_BUFFER 0x308E\n#define EGL_SINGLE_BUFFER 0x3085\n#define EGL_SWAP_BEHAVIOR 0x3093\n#define EGL_UNKNOWN EGL_CAST(EGLint,-1)\n#define EGL_VERTICAL_RESOLUTION 0x3091\n#define EGL_CONFORMANT 0x3042\n#define EGL_CONTEXT_CLIENT_VERSION 0x3098\n#define EGL_MATCH_NATIVE_PIXMAP 0x3041\n#define EGL_OPENGL_ES2_BIT 0x0004\n#define EGL_VG_ALPHA_FORMAT 0x3088\n#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B\n#define EGL_VG_ALPHA_FORMAT_PRE 0x308C\n#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040\n#define EGL_VG_COLORSPACE 0x3087\n#define EGL_VG_COLORSPACE_sRGB 0x3089\n#define EGL_VG_COLORSPACE_LINEAR 0x308A\n#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020\n#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)\n#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200\n#define EGL_MULTISAMPLE_RESOLVE 0x3099\n#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A\n#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B\n#define EGL_OPENGL_API 0x30A2\n#define EGL_OPENGL_BIT 0x0008\n#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400\n#define EGL_CONTEXT_MAJOR_VERSION 0x3098\n#define EGL_CONTEXT_MINOR_VERSION 0x30FB\n#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD\n#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD\n#define EGL_NO_RESET_NOTIFICATION 0x31BE\n#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF\n#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001\n#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002\n#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0\n#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1\n#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2\n#define EGL_OPENGL_ES3_BIT 0x00000040\n#define EGL_CL_EVENT_HANDLE 0x309C\n#define EGL_SYNC_CL_EVENT 0x30FE\n#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF\n#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0\n#define EGL_SYNC_TYPE 0x30F7\n#define EGL_SYNC_STATUS 0x30F1\n#define EGL_SYNC_CONDITION 0x30F8\n#define EGL_SIGNALED 0x30F2\n#define EGL_UNSIGNALED 0x30F3\n#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001\n#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF\n#define EGL_TIMEOUT_EXPIRED 0x30F5\n#define EGL_CONDITION_SATISFIED 0x30F6\n#define EGL_NO_SYNC EGL_CAST(EGLSync,0)\n#define EGL_SYNC_FENCE 0x30F9\n#define EGL_GL_COLORSPACE 0x309D\n#define EGL_GL_COLORSPACE_SRGB 0x3089\n#define EGL_GL_COLORSPACE_LINEAR 0x308A\n#define EGL_GL_RENDERBUFFER 0x30B9\n#define EGL_GL_TEXTURE_2D 0x30B1\n#define EGL_GL_TEXTURE_LEVEL 0x30BC\n#define EGL_GL_TEXTURE_3D 0x30B2\n#define EGL_GL_TEXTURE_ZOFFSET 0x30BD\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8\n#define EGL_IMAGE_PRESERVED 0x30D2\n#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)\nEGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);\nEGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);\nEGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);\nEGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);\nEGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);\nEGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);\nEGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx);\nEGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface);\nEGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);\nEGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);\nEGLDisplay eglGetCurrentDisplay(void);\nEGLSurface eglGetCurrentSurface(EGLint readdraw);\nEGLDisplay eglGetDisplay(EGLNativeDisplayType display_id);\nEGLint eglGetError(void);\n__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname);\nEGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);\nEGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);\nEGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);\nconst char *eglQueryString(EGLDisplay dpy, EGLint name);\nEGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);\nEGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);\nEGLBoolean eglTerminate(EGLDisplay dpy);\nEGLBoolean eglWaitGL(void);\nEGLBoolean eglWaitNative(EGLint engine);\nEGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);\nEGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);\nEGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);\nEGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);\nEGLBoolean eglBindAPI(EGLenum api);\nEGLenum eglQueryAPI(void);\nEGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);\nEGLBoolean eglReleaseThread(void);\nEGLBoolean eglWaitClient(void);\nEGLContext eglGetCurrentContext(void);\nEGLSync eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);\nEGLBoolean eglDestroySync(EGLDisplay dpy, EGLSync sync);\nEGLint eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);\nEGLBoolean eglGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);\nEGLImage eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);\nEGLBoolean eglDestroyImage(EGLDisplay dpy, EGLImage image);\nEGLDisplay eglGetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list);\nEGLSurface eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);\nEGLSurface eglCreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);\nEGLBoolean eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags);\n#define EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143\n#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001\n#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002\n#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004\n#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147\n#define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C\n#define EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID,-2)\n#define EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID,-1)\n#define EGL_TIMESTAMPS_ANDROID 0x3430\n#define EGL_COMPOSITE_DEADLINE_ANDROID 0x3431\n#define EGL_COMPOSITE_INTERVAL_ANDROID 0x3432\n#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433\n#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434\n#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435\n#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436\n#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437\n#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438\n#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439\n#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A\n#define EGL_DEQUEUE_READY_TIME_ANDROID 0x343B\n#define EGL_READS_DONE_TIME_ANDROID 0x343C\n#define EGL_NATIVE_BUFFER_ANDROID 0x3140\n#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144\n#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145\n#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146\n#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1\n#define EGL_RECORDABLE_ANDROID 0x3142\n#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200\n#define EGL_D3D9_DEVICE_ANGLE 0x33A0\n#define EGL_D3D11_DEVICE_ANGLE 0x33A1\n#define EGL_FIXED_SIZE_ANGLE 0x3201\n#define EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A\n#define EGL_DISCARD_SAMPLES_ARM 0x3286\n#define EGL_FRONT_BUFFER_EXT 0x3464\n#define EGL_BUFFER_AGE_EXT 0x313D\n#define EGL_SYNC_CLIENT_EXT 0x3364\n#define EGL_SYNC_CLIENT_SIGNAL_EXT 0x3365\n#define EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT 0x3460\n#define EGL_EXTERNAL_REF_ID_EXT 0x3461\n#define EGL_COMPOSITOR_DROP_NEWEST_FRAME_EXT 0x3462\n#define EGL_COMPOSITOR_KEEP_NEWEST_FRAME_EXT 0x3463\n#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF\n#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138\n#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE\n#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF\n#define EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT,0)\n#define EGL_BAD_DEVICE_EXT 0x322B\n#define EGL_DEVICE_EXT 0x322C\n#define EGL_DRM_DEVICE_FILE_EXT 0x3233\n#define EGL_DRM_MASTER_FD_EXT 0x333C\n#define EGL_OPENWF_DEVICE_ID_EXT 0x3237\n#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F\n#define EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340\n#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363\n#define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362\n#define EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT 0x3490\n#define EGL_GL_COLORSPACE_SCRGB_EXT 0x3351\n#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350\n#define EGL_LINUX_DMA_BUF_EXT 0x3270\n#define EGL_LINUX_DRM_FOURCC_EXT 0x3271\n#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272\n#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273\n#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274\n#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275\n#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276\n#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277\n#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278\n#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279\n#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A\n#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B\n#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C\n#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D\n#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E\n#define EGL_ITU_REC601_EXT 0x327F\n#define EGL_ITU_REC709_EXT 0x3280\n#define EGL_ITU_REC2020_EXT 0x3281\n#define EGL_YUV_FULL_RANGE_EXT 0x3282\n#define EGL_YUV_NARROW_RANGE_EXT 0x3283\n#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284\n#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285\n#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440\n#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441\n#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442\n#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443\n#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444\n#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445\n#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446\n#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447\n#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448\n#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449\n#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A\n#define EGL_GL_COLORSPACE_DEFAULT_EXT 0x314D\n#define EGL_IMPORT_SYNC_TYPE_EXT 0x3470\n#define EGL_IMPORT_IMPLICIT_SYNC_EXT 0x3471\n#define EGL_IMPORT_EXPLICIT_SYNC_EXT 0x3472\n#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134\n#define EGL_NO_OUTPUT_LAYER_EXT EGL_CAST(EGLOutputLayerEXT,0)\n#define EGL_NO_OUTPUT_PORT_EXT EGL_CAST(EGLOutputPortEXT,0)\n#define EGL_BAD_OUTPUT_LAYER_EXT 0x322D\n#define EGL_BAD_OUTPUT_PORT_EXT 0x322E\n#define EGL_SWAP_INTERVAL_EXT 0x322F\n#define EGL_DRM_CRTC_EXT 0x3234\n#define EGL_DRM_PLANE_EXT 0x3235\n#define EGL_DRM_CONNECTOR_EXT 0x3236\n#define EGL_OPENWF_PIPELINE_ID_EXT 0x3238\n#define EGL_OPENWF_PORT_ID_EXT 0x3239\n#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339\n#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A\n#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B\n#define EGL_PLATFORM_DEVICE_EXT 0x313F\n#define EGL_PLATFORM_WAYLAND_EXT 0x31D8\n#define EGL_PLATFORM_X11_EXT 0x31D5\n#define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6\n#define EGL_PROTECTED_CONTENT_EXT 0x32C0\n#define EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT 0x3360\n#define EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT 0x3361\n#define EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341\n#define EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT 0x3342\n#define EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT 0x3343\n#define EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT 0x3344\n#define EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT 0x3345\n#define EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT 0x3346\n#define EGL_SMPTE2086_WHITE_POINT_X_EXT 0x3347\n#define EGL_SMPTE2086_WHITE_POINT_Y_EXT 0x3348\n#define EGL_SMPTE2086_MAX_LUMINANCE_EXT 0x3349\n#define EGL_SMPTE2086_MIN_LUMINANCE_EXT 0x334A\n#define EGL_METADATA_SCALING_EXT 50000\n#define EGL_YUV_ORDER_EXT 0x3301\n#define EGL_YUV_NUMBER_OF_PLANES_EXT 0x3311\n#define EGL_YUV_SUBSAMPLE_EXT 0x3312\n#define EGL_YUV_DEPTH_RANGE_EXT 0x3317\n#define EGL_YUV_CSC_STANDARD_EXT 0x330A\n#define EGL_YUV_PLANE_BPP_EXT 0x331A\n#define EGL_YUV_BUFFER_EXT 0x3300\n#define EGL_YUV_ORDER_YUV_EXT 0x3302\n#define EGL_YUV_ORDER_YVU_EXT 0x3303\n#define EGL_YUV_ORDER_YUYV_EXT 0x3304\n#define EGL_YUV_ORDER_UYVY_EXT 0x3305\n#define EGL_YUV_ORDER_YVYU_EXT 0x3306\n#define EGL_YUV_ORDER_VYUY_EXT 0x3307\n#define EGL_YUV_ORDER_AYUV_EXT 0x3308\n#define EGL_YUV_SUBSAMPLE_4_2_0_EXT 0x3313\n#define EGL_YUV_SUBSAMPLE_4_2_2_EXT 0x3314\n#define EGL_YUV_SUBSAMPLE_4_4_4_EXT 0x3315\n#define EGL_YUV_DEPTH_RANGE_LIMITED_EXT 0x3318\n#define EGL_YUV_DEPTH_RANGE_FULL_EXT 0x3319\n#define EGL_YUV_CSC_STANDARD_601_EXT 0x330B\n#define EGL_YUV_CSC_STANDARD_709_EXT 0x330C\n#define EGL_YUV_CSC_STANDARD_2020_EXT 0x330D\n#define EGL_YUV_PLANE_BPP_0_EXT 0x331B\n#define EGL_YUV_PLANE_BPP_8_EXT 0x331C\n#define EGL_YUV_PLANE_BPP_10_EXT 0x331D\n#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74\n#define EGL_COLOR_FORMAT_HI 0x8F70\n#define EGL_COLOR_RGB_HI 0x8F71\n#define EGL_COLOR_RGBA_HI 0x8F72\n#define EGL_COLOR_ARGB_HI 0x8F73\n#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100\n#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101\n#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102\n#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103\n#define EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG 0x3105\n#define EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG 0x3106\n#define EGL_CL_EVENT_HANDLE_KHR 0x309C\n#define EGL_SYNC_CL_EVENT_KHR 0x30FE\n#define EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF\n#define EGL_CONFORMANT_KHR 0x3042\n#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020\n#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040\n#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0\n#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097\n#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098\n#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098\n#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB\n#define EGL_CONTEXT_FLAGS_KHR 0x30FC\n#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD\n#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD\n#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE\n#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF\n#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001\n#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002\n#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004\n#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001\n#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002\n#define EGL_OPENGL_ES3_BIT_KHR 0x00000040\n#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3\n#define EGL_OBJECT_THREAD_KHR 0x33B0\n#define EGL_OBJECT_DISPLAY_KHR 0x33B1\n#define EGL_OBJECT_CONTEXT_KHR 0x33B2\n#define EGL_OBJECT_SURFACE_KHR 0x33B3\n#define EGL_OBJECT_IMAGE_KHR 0x33B4\n#define EGL_OBJECT_SYNC_KHR 0x33B5\n#define EGL_OBJECT_STREAM_KHR 0x33B6\n#define EGL_DEBUG_MSG_CRITICAL_KHR 0x33B9\n#define EGL_DEBUG_MSG_ERROR_KHR 0x33BA\n#define EGL_DEBUG_MSG_WARN_KHR 0x33BB\n#define EGL_DEBUG_MSG_INFO_KHR 0x33BC\n#define EGL_DEBUG_CALLBACK_KHR 0x33B8\n#define EGL_TRACK_REFERENCES_KHR 0x3352\n#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0\n#define EGL_SYNC_CONDITION_KHR 0x30F8\n#define EGL_SYNC_FENCE_KHR 0x30F9\n#define EGL_GL_COLORSPACE_KHR 0x309D\n#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089\n#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A\n#define EGL_GL_RENDERBUFFER_KHR 0x30B9\n#define EGL_GL_TEXTURE_2D_KHR 0x30B1\n#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC\n#define EGL_GL_TEXTURE_3D_KHR 0x30B2\n#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8\n#define EGL_NATIVE_PIXMAP_KHR 0x30B0\n#define EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR,0)\n#define EGL_IMAGE_PRESERVED_KHR 0x30D2\n#define EGL_READ_SURFACE_BIT_KHR 0x0001\n#define EGL_WRITE_SURFACE_BIT_KHR 0x0002\n#define EGL_LOCK_SURFACE_BIT_KHR 0x0080\n#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100\n#define EGL_MATCH_FORMAT_KHR 0x3043\n#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0\n#define EGL_FORMAT_RGB_565_KHR 0x30C1\n#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2\n#define EGL_FORMAT_RGBA_8888_KHR 0x30C3\n#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4\n#define EGL_LOCK_USAGE_HINT_KHR 0x30C5\n#define EGL_BITMAP_POINTER_KHR 0x30C6\n#define EGL_BITMAP_PITCH_KHR 0x30C7\n#define EGL_BITMAP_ORIGIN_KHR 0x30C8\n#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9\n#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA\n#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB\n#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC\n#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD\n#define EGL_LOWER_LEFT_KHR 0x30CE\n#define EGL_UPPER_LEFT_KHR 0x30CF\n#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110\n#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000\n#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0)\n#define EGL_BUFFER_AGE_KHR 0x313D\n#define EGL_PLATFORM_ANDROID_KHR 0x3141\n#define EGL_PLATFORM_GBM_KHR 0x31D7\n#define EGL_PLATFORM_WAYLAND_KHR 0x31D8\n#define EGL_PLATFORM_X11_KHR 0x31D5\n#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6\n#define EGL_SYNC_STATUS_KHR 0x30F1\n#define EGL_SIGNALED_KHR 0x30F2\n#define EGL_UNSIGNALED_KHR 0x30F3\n#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5\n#define EGL_CONDITION_SATISFIED_KHR 0x30F6\n#define EGL_SYNC_TYPE_KHR 0x30F7\n#define EGL_SYNC_REUSABLE_KHR 0x30FA\n#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001\n#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFF\n#define EGL_NO_SYNC_KHR EGL_CAST(EGLSyncKHR,0)\n#define EGL_NO_STREAM_KHR EGL_CAST(EGLStreamKHR,0)\n#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210\n#define EGL_PRODUCER_FRAME_KHR 0x3212\n#define EGL_CONSUMER_FRAME_KHR 0x3213\n#define EGL_STREAM_STATE_KHR 0x3214\n#define EGL_STREAM_STATE_CREATED_KHR 0x3215\n#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216\n#define EGL_STREAM_STATE_EMPTY_KHR 0x3217\n#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218\n#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219\n#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A\n#define EGL_BAD_STREAM_KHR 0x321B\n#define EGL_BAD_STATE_KHR 0x321C\n#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E\n#define EGL_NO_FILE_DESCRIPTOR_KHR EGL_CAST(EGLNativeFileDescriptorKHR,-1)\n#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC\n#define EGL_STREAM_TIME_NOW_KHR 0x31FD\n#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE\n#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF\n#define EGL_STREAM_BIT_KHR 0x0800\n#define EGL_VG_PARENT_IMAGE_KHR 0x30BA\n#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0\n#define EGL_DRM_BUFFER_USE_MESA 0x31D1\n#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2\n#define EGL_DRM_BUFFER_MESA 0x31D3\n#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4\n#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001\n#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002\n#define EGL_DRM_BUFFER_USE_CURSOR_MESA 0x00000004\n#define EGL_PLATFORM_GBM_MESA 0x31D7\n#define EGL_PLATFORM_SURFACELESS_MESA 0x31DD\n#define EGL_Y_INVERTED_NOK 0x307F\n#define EGL_AUTO_STEREO_NV 0x3136\n#define EGL_CONTEXT_PRIORITY_REALTIME_NV 0x3357\n#define EGL_COVERAGE_BUFFERS_NV 0x30E0\n#define EGL_COVERAGE_SAMPLES_NV 0x30E1\n#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131\n#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132\n#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133\n#define EGL_CUDA_EVENT_HANDLE_NV 0x323B\n#define EGL_SYNC_CUDA_EVENT_NV 0x323C\n#define EGL_SYNC_CUDA_EVENT_COMPLETE_NV 0x323D\n#define EGL_DEPTH_ENCODING_NV 0x30E2\n#define EGL_DEPTH_ENCODING_NONE_NV 0\n#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3\n#define EGL_CUDA_DEVICE_NV 0x323A\n#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE\n#define EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C\n#define EGL_YUV_PLANE0_TEXTURE_UNIT_NV 0x332C\n#define EGL_YUV_PLANE1_TEXTURE_UNIT_NV 0x332D\n#define EGL_YUV_PLANE2_TEXTURE_UNIT_NV 0x332E\n#define EGL_STREAM_CROSS_DISPLAY_NV 0x334E\n#define EGL_STREAM_CROSS_OBJECT_NV 0x334D\n#define EGL_STREAM_CROSS_PARTITION_NV 0x323F\n#define EGL_STREAM_CROSS_PROCESS_NV 0x3245\n#define EGL_STREAM_CROSS_SYSTEM_NV 0x334F\n#define EGL_PENDING_FRAME_NV 0x3329\n#define EGL_STREAM_TIME_PENDING_NV 0x332A\n#define EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336\n#define EGL_PRODUCER_MAX_FRAME_HINT_NV 0x3337\n#define EGL_CONSUMER_MAX_FRAME_HINT_NV 0x3338\n#define EGL_MAX_STREAM_METADATA_BLOCKS_NV 0x3250\n#define EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV 0x3251\n#define EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV 0x3252\n#define EGL_PRODUCER_METADATA_NV 0x3253\n#define EGL_CONSUMER_METADATA_NV 0x3254\n#define EGL_PENDING_METADATA_NV 0x3328\n#define EGL_METADATA0_SIZE_NV 0x3255\n#define EGL_METADATA1_SIZE_NV 0x3256\n#define EGL_METADATA2_SIZE_NV 0x3257\n#define EGL_METADATA3_SIZE_NV 0x3258\n#define EGL_METADATA0_TYPE_NV 0x3259\n#define EGL_METADATA1_TYPE_NV 0x325A\n#define EGL_METADATA2_TYPE_NV 0x325B\n#define EGL_METADATA3_TYPE_NV 0x325C\n#define EGL_STREAM_STATE_INITIALIZING_NV 0x3240\n#define EGL_STREAM_TYPE_NV 0x3241\n#define EGL_STREAM_PROTOCOL_NV 0x3242\n#define EGL_STREAM_ENDPOINT_NV 0x3243\n#define EGL_STREAM_LOCAL_NV 0x3244\n#define EGL_STREAM_PRODUCER_NV 0x3247\n#define EGL_STREAM_CONSUMER_NV 0x3248\n#define EGL_STREAM_PROTOCOL_FD_NV 0x3246\n#define EGL_SUPPORT_RESET_NV 0x3334\n#define EGL_SUPPORT_REUSE_NV 0x3335\n#define EGL_STREAM_PROTOCOL_SOCKET_NV 0x324B\n#define EGL_SOCKET_HANDLE_NV 0x324C\n#define EGL_SOCKET_TYPE_NV 0x324D\n#define EGL_SOCKET_TYPE_INET_NV 0x324F\n#define EGL_SOCKET_TYPE_UNIX_NV 0x324E\n#define EGL_SYNC_NEW_FRAME_NV 0x321F\n#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6\n#define EGL_SYNC_STATUS_NV 0x30E7\n#define EGL_SIGNALED_NV 0x30E8\n#define EGL_UNSIGNALED_NV 0x30E9\n#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001\n#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFF\n#define EGL_ALREADY_SIGNALED_NV 0x30EA\n#define EGL_TIMEOUT_EXPIRED_NV 0x30EB\n#define EGL_CONDITION_SATISFIED_NV 0x30EC\n#define EGL_SYNC_TYPE_NV 0x30ED\n#define EGL_SYNC_CONDITION_NV 0x30EE\n#define EGL_SYNC_FENCE_NV 0x30EF\n#define EGL_NO_SYNC_NV EGL_CAST(EGLSyncNV,0)\n#define EGL_NATIVE_BUFFER_TIZEN 0x32A0\n#define EGL_NATIVE_SURFACE_TIZEN 0x32A1\n#ifndef EGL_ANDROID_blob_cache\n#define EGL_ANDROID_blob_cache 1\ntypedef void (APIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC)(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);\nGLAPI PFNEGLSETBLOBCACHEFUNCSANDROIDPROC glad_eglSetBlobCacheFuncsANDROID;\n#define eglSetBlobCacheFuncsANDROID glad_eglSetBlobCacheFuncsANDROID\n#endif\n#ifndef EGL_ANDROID_create_native_client_buffer\n#define EGL_ANDROID_create_native_client_buffer 1\ntypedef EGLClientBuffer (APIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC)(const EGLint *attrib_list);\nGLAPI PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC glad_eglCreateNativeClientBufferANDROID;\n#define eglCreateNativeClientBufferANDROID glad_eglCreateNativeClientBufferANDROID\n#endif\n#ifndef EGL_ANDROID_framebuffer_target\n#define EGL_ANDROID_framebuffer_target 1\n#endif\n#ifndef EGL_ANDROID_front_buffer_auto_refresh\n#define EGL_ANDROID_front_buffer_auto_refresh 1\n#endif\n#ifndef EGL_ANDROID_get_frame_timestamps\n#define EGL_ANDROID_get_frame_timestamps 1\ntypedef EGLBoolean (APIENTRYP PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC)(EGLDisplay dpy, EGLSurface surface, EGLint name);\nGLAPI PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC glad_eglGetCompositorTimingSupportedANDROID;\n#define eglGetCompositorTimingSupportedANDROID glad_eglGetCompositorTimingSupportedANDROID\ntypedef EGLBoolean (APIENTRYP PFNEGLGETCOMPOSITORTIMINGANDROIDPROC)(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);\nGLAPI PFNEGLGETCOMPOSITORTIMINGANDROIDPROC glad_eglGetCompositorTimingANDROID;\n#define eglGetCompositorTimingANDROID glad_eglGetCompositorTimingANDROID\ntypedef EGLBoolean (APIENTRYP PFNEGLGETNEXTFRAMEIDANDROIDPROC)(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);\nGLAPI PFNEGLGETNEXTFRAMEIDANDROIDPROC glad_eglGetNextFrameIdANDROID;\n#define eglGetNextFrameIdANDROID glad_eglGetNextFrameIdANDROID\ntypedef EGLBoolean (APIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC)(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);\nGLAPI PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC glad_eglGetFrameTimestampSupportedANDROID;\n#define eglGetFrameTimestampSupportedANDROID glad_eglGetFrameTimestampSupportedANDROID\ntypedef EGLBoolean (APIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROIDPROC)(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);\nGLAPI PFNEGLGETFRAMETIMESTAMPSANDROIDPROC glad_eglGetFrameTimestampsANDROID;\n#define eglGetFrameTimestampsANDROID glad_eglGetFrameTimestampsANDROID\n#endif\n#ifndef EGL_ANDROID_get_native_client_buffer\n#define EGL_ANDROID_get_native_client_buffer 1\ntypedef EGLClientBuffer (APIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC)(const struct AHardwareBuffer *buffer);\nGLAPI PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC glad_eglGetNativeClientBufferANDROID;\n#define eglGetNativeClientBufferANDROID glad_eglGetNativeClientBufferANDROID\n#endif\n#ifndef EGL_ANDROID_image_native_buffer\n#define EGL_ANDROID_image_native_buffer 1\n#endif\n#ifndef EGL_ANDROID_native_fence_sync\n#define EGL_ANDROID_native_fence_sync 1\ntypedef EGLint (APIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC)(EGLDisplay dpy, EGLSyncKHR sync);\nGLAPI PFNEGLDUPNATIVEFENCEFDANDROIDPROC glad_eglDupNativeFenceFDANDROID;\n#define eglDupNativeFenceFDANDROID glad_eglDupNativeFenceFDANDROID\n#endif\n#ifndef EGL_ANDROID_presentation_time\n#define EGL_ANDROID_presentation_time 1\ntypedef EGLBoolean (APIENTRYP PFNEGLPRESENTATIONTIMEANDROIDPROC)(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);\nGLAPI PFNEGLPRESENTATIONTIMEANDROIDPROC glad_eglPresentationTimeANDROID;\n#define eglPresentationTimeANDROID glad_eglPresentationTimeANDROID\n#endif\n#ifndef EGL_ANDROID_recordable\n#define EGL_ANDROID_recordable 1\n#endif\n#ifndef EGL_ANGLE_d3d_share_handle_client_buffer\n#define EGL_ANGLE_d3d_share_handle_client_buffer 1\n#endif\n#ifndef EGL_ANGLE_device_d3d\n#define EGL_ANGLE_device_d3d 1\n#endif\n#ifndef EGL_ANGLE_query_surface_pointer\n#define EGL_ANGLE_query_surface_pointer 1\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);\nGLAPI PFNEGLQUERYSURFACEPOINTERANGLEPROC glad_eglQuerySurfacePointerANGLE;\n#define eglQuerySurfacePointerANGLE glad_eglQuerySurfacePointerANGLE\n#endif\n#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle\n#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1\n#endif\n#ifndef EGL_ANGLE_window_fixed_size\n#define EGL_ANGLE_window_fixed_size 1\n#endif\n#ifndef EGL_ARM_implicit_external_sync\n#define EGL_ARM_implicit_external_sync 1\n#endif\n#ifndef EGL_ARM_pixmap_multisample_discard\n#define EGL_ARM_pixmap_multisample_discard 1\n#endif\n#ifndef EGL_EXT_bind_to_front\n#define EGL_EXT_bind_to_front 1\n#endif\n#ifndef EGL_EXT_buffer_age\n#define EGL_EXT_buffer_age 1\n#endif\n#ifndef EGL_EXT_client_extensions\n#define EGL_EXT_client_extensions 1\n#endif\n#ifndef EGL_EXT_client_sync\n#define EGL_EXT_client_sync 1\ntypedef EGLBoolean (APIENTRYP PFNEGLCLIENTSIGNALSYNCEXTPROC)(EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);\nGLAPI PFNEGLCLIENTSIGNALSYNCEXTPROC glad_eglClientSignalSyncEXT;\n#define eglClientSignalSyncEXT glad_eglClientSignalSyncEXT\n#endif\n#ifndef EGL_EXT_compositor\n#define EGL_EXT_compositor 1\ntypedef EGLBoolean (APIENTRYP PFNEGLCOMPOSITORSETCONTEXTLISTEXTPROC)(const EGLint *external_ref_ids, EGLint num_entries);\nGLAPI PFNEGLCOMPOSITORSETCONTEXTLISTEXTPROC glad_eglCompositorSetContextListEXT;\n#define eglCompositorSetContextListEXT glad_eglCompositorSetContextListEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLCOMPOSITORSETCONTEXTATTRIBUTESEXTPROC)(EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries);\nGLAPI PFNEGLCOMPOSITORSETCONTEXTATTRIBUTESEXTPROC glad_eglCompositorSetContextAttributesEXT;\n#define eglCompositorSetContextAttributesEXT glad_eglCompositorSetContextAttributesEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLCOMPOSITORSETWINDOWLISTEXTPROC)(EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries);\nGLAPI PFNEGLCOMPOSITORSETWINDOWLISTEXTPROC glad_eglCompositorSetWindowListEXT;\n#define eglCompositorSetWindowListEXT glad_eglCompositorSetWindowListEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLCOMPOSITORSETWINDOWATTRIBUTESEXTPROC)(EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries);\nGLAPI PFNEGLCOMPOSITORSETWINDOWATTRIBUTESEXTPROC glad_eglCompositorSetWindowAttributesEXT;\n#define eglCompositorSetWindowAttributesEXT glad_eglCompositorSetWindowAttributesEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLCOMPOSITORBINDTEXWINDOWEXTPROC)(EGLint external_win_id);\nGLAPI PFNEGLCOMPOSITORBINDTEXWINDOWEXTPROC glad_eglCompositorBindTexWindowEXT;\n#define eglCompositorBindTexWindowEXT glad_eglCompositorBindTexWindowEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLCOMPOSITORSETSIZEEXTPROC)(EGLint external_win_id, EGLint width, EGLint height);\nGLAPI PFNEGLCOMPOSITORSETSIZEEXTPROC glad_eglCompositorSetSizeEXT;\n#define eglCompositorSetSizeEXT glad_eglCompositorSetSizeEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLCOMPOSITORSWAPPOLICYEXTPROC)(EGLint external_win_id, EGLint policy);\nGLAPI PFNEGLCOMPOSITORSWAPPOLICYEXTPROC glad_eglCompositorSwapPolicyEXT;\n#define eglCompositorSwapPolicyEXT glad_eglCompositorSwapPolicyEXT\n#endif\n#ifndef EGL_EXT_create_context_robustness\n#define EGL_EXT_create_context_robustness 1\n#endif\n#ifndef EGL_EXT_device_base\n#define EGL_EXT_device_base 1\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC)(EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);\nGLAPI PFNEGLQUERYDEVICEATTRIBEXTPROC glad_eglQueryDeviceAttribEXT;\n#define eglQueryDeviceAttribEXT glad_eglQueryDeviceAttribEXT\ntypedef const char * (APIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC)(EGLDeviceEXT device, EGLint name);\nGLAPI PFNEGLQUERYDEVICESTRINGEXTPROC glad_eglQueryDeviceStringEXT;\n#define eglQueryDeviceStringEXT glad_eglQueryDeviceStringEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYDEVICESEXTPROC)(EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);\nGLAPI PFNEGLQUERYDEVICESEXTPROC glad_eglQueryDevicesEXT;\n#define eglQueryDevicesEXT glad_eglQueryDevicesEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYDISPLAYATTRIBEXTPROC)(EGLDisplay dpy, EGLint attribute, EGLAttrib *value);\nGLAPI PFNEGLQUERYDISPLAYATTRIBEXTPROC glad_eglQueryDisplayAttribEXT;\n#define eglQueryDisplayAttribEXT glad_eglQueryDisplayAttribEXT\n#endif\n#ifndef EGL_EXT_device_drm\n#define EGL_EXT_device_drm 1\n#endif\n#ifndef EGL_EXT_device_enumeration\n#define EGL_EXT_device_enumeration 1\n#endif\n#ifndef EGL_EXT_device_openwf\n#define EGL_EXT_device_openwf 1\n#endif\n#ifndef EGL_EXT_device_query\n#define EGL_EXT_device_query 1\n#endif\n#ifndef EGL_EXT_gl_colorspace_bt2020_linear\n#define EGL_EXT_gl_colorspace_bt2020_linear 1\n#endif\n#ifndef EGL_EXT_gl_colorspace_bt2020_pq\n#define EGL_EXT_gl_colorspace_bt2020_pq 1\n#endif\n#ifndef EGL_EXT_gl_colorspace_display_p3\n#define EGL_EXT_gl_colorspace_display_p3 1\n#endif\n#ifndef EGL_EXT_gl_colorspace_display_p3_linear\n#define EGL_EXT_gl_colorspace_display_p3_linear 1\n#endif\n#ifndef EGL_EXT_gl_colorspace_display_p3_passthrough\n#define EGL_EXT_gl_colorspace_display_p3_passthrough 1\n#endif\n#ifndef EGL_EXT_gl_colorspace_scrgb\n#define EGL_EXT_gl_colorspace_scrgb 1\n#endif\n#ifndef EGL_EXT_gl_colorspace_scrgb_linear\n#define EGL_EXT_gl_colorspace_scrgb_linear 1\n#endif\n#ifndef EGL_EXT_image_dma_buf_import\n#define EGL_EXT_image_dma_buf_import 1\n#endif\n#ifndef EGL_EXT_image_dma_buf_import_modifiers\n#define EGL_EXT_image_dma_buf_import_modifiers 1\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC)(EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);\nGLAPI PFNEGLQUERYDMABUFFORMATSEXTPROC glad_eglQueryDmaBufFormatsEXT;\n#define eglQueryDmaBufFormatsEXT glad_eglQueryDmaBufFormatsEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC)(EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);\nGLAPI PFNEGLQUERYDMABUFMODIFIERSEXTPROC glad_eglQueryDmaBufModifiersEXT;\n#define eglQueryDmaBufModifiersEXT glad_eglQueryDmaBufModifiersEXT\n#endif\n#ifndef EGL_EXT_image_gl_colorspace\n#define EGL_EXT_image_gl_colorspace 1\n#endif\n#ifndef EGL_EXT_image_implicit_sync_control\n#define EGL_EXT_image_implicit_sync_control 1\n#endif\n#ifndef EGL_EXT_multiview_window\n#define EGL_EXT_multiview_window 1\n#endif\n#ifndef EGL_EXT_output_base\n#define EGL_EXT_output_base 1\ntypedef EGLBoolean (APIENTRYP PFNEGLGETOUTPUTLAYERSEXTPROC)(EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);\nGLAPI PFNEGLGETOUTPUTLAYERSEXTPROC glad_eglGetOutputLayersEXT;\n#define eglGetOutputLayersEXT glad_eglGetOutputLayersEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLGETOUTPUTPORTSEXTPROC)(EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);\nGLAPI PFNEGLGETOUTPUTPORTSEXTPROC glad_eglGetOutputPortsEXT;\n#define eglGetOutputPortsEXT glad_eglGetOutputPortsEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLOUTPUTLAYERATTRIBEXTPROC)(EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);\nGLAPI PFNEGLOUTPUTLAYERATTRIBEXTPROC glad_eglOutputLayerAttribEXT;\n#define eglOutputLayerAttribEXT glad_eglOutputLayerAttribEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC)(EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);\nGLAPI PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC glad_eglQueryOutputLayerAttribEXT;\n#define eglQueryOutputLayerAttribEXT glad_eglQueryOutputLayerAttribEXT\ntypedef const char * (APIENTRYP PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC)(EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);\nGLAPI PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC glad_eglQueryOutputLayerStringEXT;\n#define eglQueryOutputLayerStringEXT glad_eglQueryOutputLayerStringEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLOUTPUTPORTATTRIBEXTPROC)(EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);\nGLAPI PFNEGLOUTPUTPORTATTRIBEXTPROC glad_eglOutputPortAttribEXT;\n#define eglOutputPortAttribEXT glad_eglOutputPortAttribEXT\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC)(EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);\nGLAPI PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC glad_eglQueryOutputPortAttribEXT;\n#define eglQueryOutputPortAttribEXT glad_eglQueryOutputPortAttribEXT\ntypedef const char * (APIENTRYP PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC)(EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);\nGLAPI PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC glad_eglQueryOutputPortStringEXT;\n#define eglQueryOutputPortStringEXT glad_eglQueryOutputPortStringEXT\n#endif\n#ifndef EGL_EXT_output_drm\n#define EGL_EXT_output_drm 1\n#endif\n#ifndef EGL_EXT_output_openwf\n#define EGL_EXT_output_openwf 1\n#endif\n#ifndef EGL_EXT_pixel_format_float\n#define EGL_EXT_pixel_format_float 1\n#endif\n#ifndef EGL_EXT_platform_base\n#define EGL_EXT_platform_base 1\ntypedef EGLDisplay (APIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum platform, void *native_display, const EGLint *attrib_list);\nGLAPI PFNEGLGETPLATFORMDISPLAYEXTPROC glad_eglGetPlatformDisplayEXT;\n#define eglGetPlatformDisplayEXT glad_eglGetPlatformDisplayEXT\ntypedef EGLSurface (APIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);\nGLAPI PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC glad_eglCreatePlatformWindowSurfaceEXT;\n#define eglCreatePlatformWindowSurfaceEXT glad_eglCreatePlatformWindowSurfaceEXT\ntypedef EGLSurface (APIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC)(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);\nGLAPI PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC glad_eglCreatePlatformPixmapSurfaceEXT;\n#define eglCreatePlatformPixmapSurfaceEXT glad_eglCreatePlatformPixmapSurfaceEXT\n#endif\n#ifndef EGL_EXT_platform_device\n#define EGL_EXT_platform_device 1\n#endif\n#ifndef EGL_EXT_platform_wayland\n#define EGL_EXT_platform_wayland 1\n#endif\n#ifndef EGL_EXT_platform_x11\n#define EGL_EXT_platform_x11 1\n#endif\n#ifndef EGL_EXT_protected_content\n#define EGL_EXT_protected_content 1\n#endif\n#ifndef EGL_EXT_protected_surface\n#define EGL_EXT_protected_surface 1\n#endif\n#ifndef EGL_EXT_stream_consumer_egloutput\n#define EGL_EXT_stream_consumer_egloutput 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMCONSUMEROUTPUTEXTPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);\nGLAPI PFNEGLSTREAMCONSUMEROUTPUTEXTPROC glad_eglStreamConsumerOutputEXT;\n#define eglStreamConsumerOutputEXT glad_eglStreamConsumerOutputEXT\n#endif\n#ifndef EGL_EXT_surface_CTA861_3_metadata\n#define EGL_EXT_surface_CTA861_3_metadata 1\n#endif\n#ifndef EGL_EXT_surface_SMPTE2086_metadata\n#define EGL_EXT_surface_SMPTE2086_metadata 1\n#endif\n#ifndef EGL_EXT_swap_buffers_with_damage\n#define EGL_EXT_swap_buffers_with_damage 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);\nGLAPI PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC glad_eglSwapBuffersWithDamageEXT;\n#define eglSwapBuffersWithDamageEXT glad_eglSwapBuffersWithDamageEXT\n#endif\n#ifndef EGL_EXT_sync_reuse\n#define EGL_EXT_sync_reuse 1\ntypedef EGLBoolean (APIENTRYP PFNEGLUNSIGNALSYNCEXTPROC)(EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);\nGLAPI PFNEGLUNSIGNALSYNCEXTPROC glad_eglUnsignalSyncEXT;\n#define eglUnsignalSyncEXT glad_eglUnsignalSyncEXT\n#endif\n#ifndef EGL_EXT_yuv_surface\n#define EGL_EXT_yuv_surface 1\n#endif\n#ifndef EGL_HI_clientpixmap\n#define EGL_HI_clientpixmap 1\ntypedef EGLSurface (APIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC)(EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);\nGLAPI PFNEGLCREATEPIXMAPSURFACEHIPROC glad_eglCreatePixmapSurfaceHI;\n#define eglCreatePixmapSurfaceHI glad_eglCreatePixmapSurfaceHI\n#endif\n#ifndef EGL_HI_colorformats\n#define EGL_HI_colorformats 1\n#endif\n#ifndef EGL_IMG_context_priority\n#define EGL_IMG_context_priority 1\n#endif\n#ifndef EGL_IMG_image_plane_attribs\n#define EGL_IMG_image_plane_attribs 1\n#endif\n#ifndef EGL_KHR_cl_event\n#define EGL_KHR_cl_event 1\n#endif\n#ifndef EGL_KHR_cl_event2\n#define EGL_KHR_cl_event2 1\ntypedef EGLSyncKHR (APIENTRYP PFNEGLCREATESYNC64KHRPROC)(EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);\nGLAPI PFNEGLCREATESYNC64KHRPROC glad_eglCreateSync64KHR;\n#define eglCreateSync64KHR glad_eglCreateSync64KHR\n#endif\n#ifndef EGL_KHR_client_get_all_proc_addresses\n#define EGL_KHR_client_get_all_proc_addresses 1\n#endif\n#ifndef EGL_KHR_config_attribs\n#define EGL_KHR_config_attribs 1\n#endif\n#ifndef EGL_KHR_context_flush_control\n#define EGL_KHR_context_flush_control 1\n#endif\n#ifndef EGL_KHR_create_context\n#define EGL_KHR_create_context 1\n#endif\n#ifndef EGL_KHR_create_context_no_error\n#define EGL_KHR_create_context_no_error 1\n#endif\n#ifndef EGL_KHR_debug\n#define EGL_KHR_debug 1\ntypedef EGLint (APIENTRYP PFNEGLDEBUGMESSAGECONTROLKHRPROC)(EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list);\nGLAPI PFNEGLDEBUGMESSAGECONTROLKHRPROC glad_eglDebugMessageControlKHR;\n#define eglDebugMessageControlKHR glad_eglDebugMessageControlKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYDEBUGKHRPROC)(EGLint attribute, EGLAttrib *value);\nGLAPI PFNEGLQUERYDEBUGKHRPROC glad_eglQueryDebugKHR;\n#define eglQueryDebugKHR glad_eglQueryDebugKHR\ntypedef EGLint (APIENTRYP PFNEGLLABELOBJECTKHRPROC)(EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label);\nGLAPI PFNEGLLABELOBJECTKHRPROC glad_eglLabelObjectKHR;\n#define eglLabelObjectKHR glad_eglLabelObjectKHR\n#endif\n#ifndef EGL_KHR_display_reference\n#define EGL_KHR_display_reference 1\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYDISPLAYATTRIBKHRPROC)(EGLDisplay dpy, EGLint name, EGLAttrib *value);\nGLAPI PFNEGLQUERYDISPLAYATTRIBKHRPROC glad_eglQueryDisplayAttribKHR;\n#define eglQueryDisplayAttribKHR glad_eglQueryDisplayAttribKHR\n#endif\n#ifndef EGL_KHR_fence_sync\n#define EGL_KHR_fence_sync 1\ntypedef EGLSyncKHR (APIENTRYP PFNEGLCREATESYNCKHRPROC)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);\nGLAPI PFNEGLCREATESYNCKHRPROC glad_eglCreateSyncKHR;\n#define eglCreateSyncKHR glad_eglCreateSyncKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLDESTROYSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync);\nGLAPI PFNEGLDESTROYSYNCKHRPROC glad_eglDestroySyncKHR;\n#define eglDestroySyncKHR glad_eglDestroySyncKHR\ntypedef EGLint (APIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);\nGLAPI PFNEGLCLIENTWAITSYNCKHRPROC glad_eglClientWaitSyncKHR;\n#define eglClientWaitSyncKHR glad_eglClientWaitSyncKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLGETSYNCATTRIBKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);\nGLAPI PFNEGLGETSYNCATTRIBKHRPROC glad_eglGetSyncAttribKHR;\n#define eglGetSyncAttribKHR glad_eglGetSyncAttribKHR\n#endif\n#ifndef EGL_KHR_get_all_proc_addresses\n#define EGL_KHR_get_all_proc_addresses 1\n#endif\n#ifndef EGL_KHR_gl_colorspace\n#define EGL_KHR_gl_colorspace 1\n#endif\n#ifndef EGL_KHR_gl_renderbuffer_image\n#define EGL_KHR_gl_renderbuffer_image 1\n#endif\n#ifndef EGL_KHR_gl_texture_2D_image\n#define EGL_KHR_gl_texture_2D_image 1\n#endif\n#ifndef EGL_KHR_gl_texture_3D_image\n#define EGL_KHR_gl_texture_3D_image 1\n#endif\n#ifndef EGL_KHR_gl_texture_cubemap_image\n#define EGL_KHR_gl_texture_cubemap_image 1\n#endif\n#ifndef EGL_KHR_image\n#define EGL_KHR_image 1\ntypedef EGLImageKHR (APIENTRYP PFNEGLCREATEIMAGEKHRPROC)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);\nGLAPI PFNEGLCREATEIMAGEKHRPROC glad_eglCreateImageKHR;\n#define eglCreateImageKHR glad_eglCreateImageKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLDESTROYIMAGEKHRPROC)(EGLDisplay dpy, EGLImageKHR image);\nGLAPI PFNEGLDESTROYIMAGEKHRPROC glad_eglDestroyImageKHR;\n#define eglDestroyImageKHR glad_eglDestroyImageKHR\n#endif\n#ifndef EGL_KHR_image_base\n#define EGL_KHR_image_base 1\n#endif\n#ifndef EGL_KHR_image_pixmap\n#define EGL_KHR_image_pixmap 1\n#endif\n#ifndef EGL_KHR_lock_surface\n#define EGL_KHR_lock_surface 1\ntypedef EGLBoolean (APIENTRYP PFNEGLLOCKSURFACEKHRPROC)(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);\nGLAPI PFNEGLLOCKSURFACEKHRPROC glad_eglLockSurfaceKHR;\n#define eglLockSurfaceKHR glad_eglLockSurfaceKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLUNLOCKSURFACEKHRPROC)(EGLDisplay dpy, EGLSurface surface);\nGLAPI PFNEGLUNLOCKSURFACEKHRPROC glad_eglUnlockSurfaceKHR;\n#define eglUnlockSurfaceKHR glad_eglUnlockSurfaceKHR\n#endif\n#ifndef EGL_KHR_lock_surface2\n#define EGL_KHR_lock_surface2 1\n#endif\n#ifndef EGL_KHR_lock_surface3\n#define EGL_KHR_lock_surface3 1\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYSURFACE64KHRPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);\nGLAPI PFNEGLQUERYSURFACE64KHRPROC glad_eglQuerySurface64KHR;\n#define eglQuerySurface64KHR glad_eglQuerySurface64KHR\n#endif\n#ifndef EGL_KHR_mutable_render_buffer\n#define EGL_KHR_mutable_render_buffer 1\n#endif\n#ifndef EGL_KHR_no_config_context\n#define EGL_KHR_no_config_context 1\n#endif\n#ifndef EGL_KHR_partial_update\n#define EGL_KHR_partial_update 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSETDAMAGEREGIONKHRPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);\nGLAPI PFNEGLSETDAMAGEREGIONKHRPROC glad_eglSetDamageRegionKHR;\n#define eglSetDamageRegionKHR glad_eglSetDamageRegionKHR\n#endif\n#ifndef EGL_KHR_platform_android\n#define EGL_KHR_platform_android 1\n#endif\n#ifndef EGL_KHR_platform_gbm\n#define EGL_KHR_platform_gbm 1\n#endif\n#ifndef EGL_KHR_platform_wayland\n#define EGL_KHR_platform_wayland 1\n#endif\n#ifndef EGL_KHR_platform_x11\n#define EGL_KHR_platform_x11 1\n#endif\n#ifndef EGL_KHR_reusable_sync\n#define EGL_KHR_reusable_sync 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSIGNALSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);\nGLAPI PFNEGLSIGNALSYNCKHRPROC glad_eglSignalSyncKHR;\n#define eglSignalSyncKHR glad_eglSignalSyncKHR\n#endif\n#ifndef EGL_KHR_stream\n#define EGL_KHR_stream 1\ntypedef EGLStreamKHR (APIENTRYP PFNEGLCREATESTREAMKHRPROC)(EGLDisplay dpy, const EGLint *attrib_list);\nGLAPI PFNEGLCREATESTREAMKHRPROC glad_eglCreateStreamKHR;\n#define eglCreateStreamKHR glad_eglCreateStreamKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLDESTROYSTREAMKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);\nGLAPI PFNEGLDESTROYSTREAMKHRPROC glad_eglDestroyStreamKHR;\n#define eglDestroyStreamKHR glad_eglDestroyStreamKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMATTRIBKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);\nGLAPI PFNEGLSTREAMATTRIBKHRPROC glad_eglStreamAttribKHR;\n#define eglStreamAttribKHR glad_eglStreamAttribKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYSTREAMKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);\nGLAPI PFNEGLQUERYSTREAMKHRPROC glad_eglQueryStreamKHR;\n#define eglQueryStreamKHR glad_eglQueryStreamKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYSTREAMU64KHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);\nGLAPI PFNEGLQUERYSTREAMU64KHRPROC glad_eglQueryStreamu64KHR;\n#define eglQueryStreamu64KHR glad_eglQueryStreamu64KHR\n#endif\n#ifndef EGL_KHR_stream_attrib\n#define EGL_KHR_stream_attrib 1\ntypedef EGLStreamKHR (APIENTRYP PFNEGLCREATESTREAMATTRIBKHRPROC)(EGLDisplay dpy, const EGLAttrib *attrib_list);\nGLAPI PFNEGLCREATESTREAMATTRIBKHRPROC glad_eglCreateStreamAttribKHR;\n#define eglCreateStreamAttribKHR glad_eglCreateStreamAttribKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLSETSTREAMATTRIBKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);\nGLAPI PFNEGLSETSTREAMATTRIBKHRPROC glad_eglSetStreamAttribKHR;\n#define eglSetStreamAttribKHR glad_eglSetStreamAttribKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYSTREAMATTRIBKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);\nGLAPI PFNEGLQUERYSTREAMATTRIBKHRPROC glad_eglQueryStreamAttribKHR;\n#define eglQueryStreamAttribKHR glad_eglQueryStreamAttribKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);\nGLAPI PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC glad_eglStreamConsumerAcquireAttribKHR;\n#define eglStreamConsumerAcquireAttribKHR glad_eglStreamConsumerAcquireAttribKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);\nGLAPI PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC glad_eglStreamConsumerReleaseAttribKHR;\n#define eglStreamConsumerReleaseAttribKHR glad_eglStreamConsumerReleaseAttribKHR\n#endif\n#ifndef EGL_KHR_stream_consumer_gltexture\n#define EGL_KHR_stream_consumer_gltexture 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);\nGLAPI PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC glad_eglStreamConsumerGLTextureExternalKHR;\n#define eglStreamConsumerGLTextureExternalKHR glad_eglStreamConsumerGLTextureExternalKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);\nGLAPI PFNEGLSTREAMCONSUMERACQUIREKHRPROC glad_eglStreamConsumerAcquireKHR;\n#define eglStreamConsumerAcquireKHR glad_eglStreamConsumerAcquireKHR\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);\nGLAPI PFNEGLSTREAMCONSUMERRELEASEKHRPROC glad_eglStreamConsumerReleaseKHR;\n#define eglStreamConsumerReleaseKHR glad_eglStreamConsumerReleaseKHR\n#endif\n#ifndef EGL_KHR_stream_cross_process_fd\n#define EGL_KHR_stream_cross_process_fd 1\ntypedef EGLNativeFileDescriptorKHR (APIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream);\nGLAPI PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC glad_eglGetStreamFileDescriptorKHR;\n#define eglGetStreamFileDescriptorKHR glad_eglGetStreamFileDescriptorKHR\ntypedef EGLStreamKHR (APIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC)(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);\nGLAPI PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC glad_eglCreateStreamFromFileDescriptorKHR;\n#define eglCreateStreamFromFileDescriptorKHR glad_eglCreateStreamFromFileDescriptorKHR\n#endif\n#ifndef EGL_KHR_stream_fifo\n#define EGL_KHR_stream_fifo 1\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);\nGLAPI PFNEGLQUERYSTREAMTIMEKHRPROC glad_eglQueryStreamTimeKHR;\n#define eglQueryStreamTimeKHR glad_eglQueryStreamTimeKHR\n#endif\n#ifndef EGL_KHR_stream_producer_aldatalocator\n#define EGL_KHR_stream_producer_aldatalocator 1\n#endif\n#ifndef EGL_KHR_stream_producer_eglsurface\n#define EGL_KHR_stream_producer_eglsurface 1\ntypedef EGLSurface (APIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC)(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);\nGLAPI PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC glad_eglCreateStreamProducerSurfaceKHR;\n#define eglCreateStreamProducerSurfaceKHR glad_eglCreateStreamProducerSurfaceKHR\n#endif\n#ifndef EGL_KHR_surfaceless_context\n#define EGL_KHR_surfaceless_context 1\n#endif\n#ifndef EGL_KHR_swap_buffers_with_damage\n#define EGL_KHR_swap_buffers_with_damage 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);\nGLAPI PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC glad_eglSwapBuffersWithDamageKHR;\n#define eglSwapBuffersWithDamageKHR glad_eglSwapBuffersWithDamageKHR\n#endif\n#ifndef EGL_KHR_vg_parent_image\n#define EGL_KHR_vg_parent_image 1\n#endif\n#ifndef EGL_KHR_wait_sync\n#define EGL_KHR_wait_sync 1\ntypedef EGLint (APIENTRYP PFNEGLWAITSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);\nGLAPI PFNEGLWAITSYNCKHRPROC glad_eglWaitSyncKHR;\n#define eglWaitSyncKHR glad_eglWaitSyncKHR\n#endif\n#ifndef EGL_MESA_drm_image\n#define EGL_MESA_drm_image 1\ntypedef EGLImageKHR (APIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC)(EGLDisplay dpy, const EGLint *attrib_list);\nGLAPI PFNEGLCREATEDRMIMAGEMESAPROC glad_eglCreateDRMImageMESA;\n#define eglCreateDRMImageMESA glad_eglCreateDRMImageMESA\ntypedef EGLBoolean (APIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC)(EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);\nGLAPI PFNEGLEXPORTDRMIMAGEMESAPROC glad_eglExportDRMImageMESA;\n#define eglExportDRMImageMESA glad_eglExportDRMImageMESA\n#endif\n#ifndef EGL_MESA_image_dma_buf_export\n#define EGL_MESA_image_dma_buf_export 1\ntypedef EGLBoolean (APIENTRYP PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC)(EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);\nGLAPI PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC glad_eglExportDMABUFImageQueryMESA;\n#define eglExportDMABUFImageQueryMESA glad_eglExportDMABUFImageQueryMESA\ntypedef EGLBoolean (APIENTRYP PFNEGLEXPORTDMABUFIMAGEMESAPROC)(EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);\nGLAPI PFNEGLEXPORTDMABUFIMAGEMESAPROC glad_eglExportDMABUFImageMESA;\n#define eglExportDMABUFImageMESA glad_eglExportDMABUFImageMESA\n#endif\n#ifndef EGL_MESA_platform_gbm\n#define EGL_MESA_platform_gbm 1\n#endif\n#ifndef EGL_MESA_platform_surfaceless\n#define EGL_MESA_platform_surfaceless 1\n#endif\n#ifndef EGL_NOK_swap_region\n#define EGL_NOK_swap_region 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSWAPBUFFERSREGIONNOKPROC)(EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);\nGLAPI PFNEGLSWAPBUFFERSREGIONNOKPROC glad_eglSwapBuffersRegionNOK;\n#define eglSwapBuffersRegionNOK glad_eglSwapBuffersRegionNOK\n#endif\n#ifndef EGL_NOK_swap_region2\n#define EGL_NOK_swap_region2 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSWAPBUFFERSREGION2NOKPROC)(EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);\nGLAPI PFNEGLSWAPBUFFERSREGION2NOKPROC glad_eglSwapBuffersRegion2NOK;\n#define eglSwapBuffersRegion2NOK glad_eglSwapBuffersRegion2NOK\n#endif\n#ifndef EGL_NOK_texture_from_pixmap\n#define EGL_NOK_texture_from_pixmap 1\n#endif\n#ifndef EGL_NV_3dvision_surface\n#define EGL_NV_3dvision_surface 1\n#endif\n#ifndef EGL_NV_context_priority_realtime\n#define EGL_NV_context_priority_realtime 1\n#endif\n#ifndef EGL_NV_coverage_sample\n#define EGL_NV_coverage_sample 1\n#endif\n#ifndef EGL_NV_coverage_sample_resolve\n#define EGL_NV_coverage_sample_resolve 1\n#endif\n#ifndef EGL_NV_cuda_event\n#define EGL_NV_cuda_event 1\n#endif\n#ifndef EGL_NV_depth_nonlinear\n#define EGL_NV_depth_nonlinear 1\n#endif\n#ifndef EGL_NV_device_cuda\n#define EGL_NV_device_cuda 1\n#endif\n#ifndef EGL_NV_native_query\n#define EGL_NV_native_query 1\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC)(EGLDisplay dpy, EGLNativeDisplayType *display_id);\nGLAPI PFNEGLQUERYNATIVEDISPLAYNVPROC glad_eglQueryNativeDisplayNV;\n#define eglQueryNativeDisplayNV glad_eglQueryNativeDisplayNV\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC)(EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);\nGLAPI PFNEGLQUERYNATIVEWINDOWNVPROC glad_eglQueryNativeWindowNV;\n#define eglQueryNativeWindowNV glad_eglQueryNativeWindowNV\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC)(EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);\nGLAPI PFNEGLQUERYNATIVEPIXMAPNVPROC glad_eglQueryNativePixmapNV;\n#define eglQueryNativePixmapNV glad_eglQueryNativePixmapNV\n#endif\n#ifndef EGL_NV_post_convert_rounding\n#define EGL_NV_post_convert_rounding 1\n#endif\n#ifndef EGL_NV_post_sub_buffer\n#define EGL_NV_post_sub_buffer 1\ntypedef EGLBoolean (APIENTRYP PFNEGLPOSTSUBBUFFERNVPROC)(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);\nGLAPI PFNEGLPOSTSUBBUFFERNVPROC glad_eglPostSubBufferNV;\n#define eglPostSubBufferNV glad_eglPostSubBufferNV\n#endif\n#ifndef EGL_NV_robustness_video_memory_purge\n#define EGL_NV_robustness_video_memory_purge 1\n#endif\n#ifndef EGL_NV_stream_consumer_gltexture_yuv\n#define EGL_NV_stream_consumer_gltexture_yuv 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC)(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);\nGLAPI PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC glad_eglStreamConsumerGLTextureExternalAttribsNV;\n#define eglStreamConsumerGLTextureExternalAttribsNV glad_eglStreamConsumerGLTextureExternalAttribsNV\n#endif\n#ifndef EGL_NV_stream_cross_display\n#define EGL_NV_stream_cross_display 1\n#endif\n#ifndef EGL_NV_stream_cross_object\n#define EGL_NV_stream_cross_object 1\n#endif\n#ifndef EGL_NV_stream_cross_partition\n#define EGL_NV_stream_cross_partition 1\n#endif\n#ifndef EGL_NV_stream_cross_process\n#define EGL_NV_stream_cross_process 1\n#endif\n#ifndef EGL_NV_stream_cross_system\n#define EGL_NV_stream_cross_system 1\n#endif\n#ifndef EGL_NV_stream_fifo_next\n#define EGL_NV_stream_fifo_next 1\n#endif\n#ifndef EGL_NV_stream_fifo_synchronous\n#define EGL_NV_stream_fifo_synchronous 1\n#endif\n#ifndef EGL_NV_stream_flush\n#define EGL_NV_stream_flush 1\ntypedef EGLBoolean (APIENTRYP PFNEGLSTREAMFLUSHNVPROC)(EGLDisplay dpy, EGLStreamKHR stream);\nGLAPI PFNEGLSTREAMFLUSHNVPROC glad_eglStreamFlushNV;\n#define eglStreamFlushNV glad_eglStreamFlushNV\n#endif\n#ifndef EGL_NV_stream_frame_limits\n#define EGL_NV_stream_frame_limits 1\n#endif\n#ifndef EGL_NV_stream_metadata\n#define EGL_NV_stream_metadata 1\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYDISPLAYATTRIBNVPROC)(EGLDisplay dpy, EGLint attribute, EGLAttrib *value);\nGLAPI PFNEGLQUERYDISPLAYATTRIBNVPROC glad_eglQueryDisplayAttribNV;\n#define eglQueryDisplayAttribNV glad_eglQueryDisplayAttribNV\ntypedef EGLBoolean (APIENTRYP PFNEGLSETSTREAMMETADATANVPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data);\nGLAPI PFNEGLSETSTREAMMETADATANVPROC glad_eglSetStreamMetadataNV;\n#define eglSetStreamMetadataNV glad_eglSetStreamMetadataNV\ntypedef EGLBoolean (APIENTRYP PFNEGLQUERYSTREAMMETADATANVPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data);\nGLAPI PFNEGLQUERYSTREAMMETADATANVPROC glad_eglQueryStreamMetadataNV;\n#define eglQueryStreamMetadataNV glad_eglQueryStreamMetadataNV\n#endif\n#ifndef EGL_NV_stream_remote\n#define EGL_NV_stream_remote 1\n#endif\n#ifndef EGL_NV_stream_reset\n#define EGL_NV_stream_reset 1\ntypedef EGLBoolean (APIENTRYP PFNEGLRESETSTREAMNVPROC)(EGLDisplay dpy, EGLStreamKHR stream);\nGLAPI PFNEGLRESETSTREAMNVPROC glad_eglResetStreamNV;\n#define eglResetStreamNV glad_eglResetStreamNV\n#endif\n#ifndef EGL_NV_stream_socket\n#define EGL_NV_stream_socket 1\n#endif\n#ifndef EGL_NV_stream_socket_inet\n#define EGL_NV_stream_socket_inet 1\n#endif\n#ifndef EGL_NV_stream_socket_unix\n#define EGL_NV_stream_socket_unix 1\n#endif\n#ifndef EGL_NV_stream_sync\n#define EGL_NV_stream_sync 1\ntypedef EGLSyncKHR (APIENTRYP PFNEGLCREATESTREAMSYNCNVPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);\nGLAPI PFNEGLCREATESTREAMSYNCNVPROC glad_eglCreateStreamSyncNV;\n#define eglCreateStreamSyncNV glad_eglCreateStreamSyncNV\n#endif\n#ifndef EGL_NV_sync\n#define EGL_NV_sync 1\ntypedef EGLSyncNV (APIENTRYP PFNEGLCREATEFENCESYNCNVPROC)(EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);\nGLAPI PFNEGLCREATEFENCESYNCNVPROC glad_eglCreateFenceSyncNV;\n#define eglCreateFenceSyncNV glad_eglCreateFenceSyncNV\ntypedef EGLBoolean (APIENTRYP PFNEGLDESTROYSYNCNVPROC)(EGLSyncNV sync);\nGLAPI PFNEGLDESTROYSYNCNVPROC glad_eglDestroySyncNV;\n#define eglDestroySyncNV glad_eglDestroySyncNV\ntypedef EGLBoolean (APIENTRYP PFNEGLFENCENVPROC)(EGLSyncNV sync);\nGLAPI PFNEGLFENCENVPROC glad_eglFenceNV;\n#define eglFenceNV glad_eglFenceNV\ntypedef EGLint (APIENTRYP PFNEGLCLIENTWAITSYNCNVPROC)(EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);\nGLAPI PFNEGLCLIENTWAITSYNCNVPROC glad_eglClientWaitSyncNV;\n#define eglClientWaitSyncNV glad_eglClientWaitSyncNV\ntypedef EGLBoolean (APIENTRYP PFNEGLSIGNALSYNCNVPROC)(EGLSyncNV sync, EGLenum mode);\nGLAPI PFNEGLSIGNALSYNCNVPROC glad_eglSignalSyncNV;\n#define eglSignalSyncNV glad_eglSignalSyncNV\ntypedef EGLBoolean (APIENTRYP PFNEGLGETSYNCATTRIBNVPROC)(EGLSyncNV sync, EGLint attribute, EGLint *value);\nGLAPI PFNEGLGETSYNCATTRIBNVPROC glad_eglGetSyncAttribNV;\n#define eglGetSyncAttribNV glad_eglGetSyncAttribNV\n#endif\n#ifndef EGL_NV_system_time\n#define EGL_NV_system_time 1\ntypedef EGLuint64NV (APIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)(void);\nGLAPI PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC glad_eglGetSystemTimeFrequencyNV;\n#define eglGetSystemTimeFrequencyNV glad_eglGetSystemTimeFrequencyNV\ntypedef EGLuint64NV (APIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void);\nGLAPI PFNEGLGETSYSTEMTIMENVPROC glad_eglGetSystemTimeNV;\n#define eglGetSystemTimeNV glad_eglGetSystemTimeNV\n#endif\n#ifndef EGL_TIZEN_image_native_buffer\n#define EGL_TIZEN_image_native_buffer 1\n#endif\n#ifndef EGL_TIZEN_image_native_surface\n#define EGL_TIZEN_image_native_surface 1\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/3rdparty/glad/src/glad_egl.c",
    "content": "/*\n\n    EGL loader generated by glad 0.1.25 on Mon Jan 14 16:56:21 2019.\n\n    Language/Generator: C/C++\n    Specification: egl\n    APIs: egl=1.5\n    Profile: -\n    Extensions:\n        EGL_ANDROID_blob_cache,\n        EGL_ANDROID_create_native_client_buffer,\n        EGL_ANDROID_framebuffer_target,\n        EGL_ANDROID_front_buffer_auto_refresh,\n        EGL_ANDROID_get_frame_timestamps,\n        EGL_ANDROID_get_native_client_buffer,\n        EGL_ANDROID_image_native_buffer,\n        EGL_ANDROID_native_fence_sync,\n        EGL_ANDROID_presentation_time,\n        EGL_ANDROID_recordable,\n        EGL_ANGLE_d3d_share_handle_client_buffer,\n        EGL_ANGLE_device_d3d,\n        EGL_ANGLE_query_surface_pointer,\n        EGL_ANGLE_surface_d3d_texture_2d_share_handle,\n        EGL_ANGLE_window_fixed_size,\n        EGL_ARM_implicit_external_sync,\n        EGL_ARM_pixmap_multisample_discard,\n        EGL_EXT_bind_to_front,\n        EGL_EXT_buffer_age,\n        EGL_EXT_client_extensions,\n        EGL_EXT_client_sync,\n        EGL_EXT_compositor,\n        EGL_EXT_create_context_robustness,\n        EGL_EXT_device_base,\n        EGL_EXT_device_drm,\n        EGL_EXT_device_enumeration,\n        EGL_EXT_device_openwf,\n        EGL_EXT_device_query,\n        EGL_EXT_gl_colorspace_bt2020_linear,\n        EGL_EXT_gl_colorspace_bt2020_pq,\n        EGL_EXT_gl_colorspace_display_p3,\n        EGL_EXT_gl_colorspace_display_p3_linear,\n        EGL_EXT_gl_colorspace_display_p3_passthrough,\n        EGL_EXT_gl_colorspace_scrgb,\n        EGL_EXT_gl_colorspace_scrgb_linear,\n        EGL_EXT_image_dma_buf_import,\n        EGL_EXT_image_dma_buf_import_modifiers,\n        EGL_EXT_image_gl_colorspace,\n        EGL_EXT_image_implicit_sync_control,\n        EGL_EXT_multiview_window,\n        EGL_EXT_output_base,\n        EGL_EXT_output_drm,\n        EGL_EXT_output_openwf,\n        EGL_EXT_pixel_format_float,\n        EGL_EXT_platform_base,\n        EGL_EXT_platform_device,\n        EGL_EXT_platform_wayland,\n        EGL_EXT_platform_x11,\n        EGL_EXT_protected_content,\n        EGL_EXT_protected_surface,\n        EGL_EXT_stream_consumer_egloutput,\n        EGL_EXT_surface_CTA861_3_metadata,\n        EGL_EXT_surface_SMPTE2086_metadata,\n        EGL_EXT_swap_buffers_with_damage,\n        EGL_EXT_sync_reuse,\n        EGL_EXT_yuv_surface,\n        EGL_HI_clientpixmap,\n        EGL_HI_colorformats,\n        EGL_IMG_context_priority,\n        EGL_IMG_image_plane_attribs,\n        EGL_KHR_cl_event,\n        EGL_KHR_cl_event2,\n        EGL_KHR_client_get_all_proc_addresses,\n        EGL_KHR_config_attribs,\n        EGL_KHR_context_flush_control,\n        EGL_KHR_create_context,\n        EGL_KHR_create_context_no_error,\n        EGL_KHR_debug,\n        EGL_KHR_display_reference,\n        EGL_KHR_fence_sync,\n        EGL_KHR_get_all_proc_addresses,\n        EGL_KHR_gl_colorspace,\n        EGL_KHR_gl_renderbuffer_image,\n        EGL_KHR_gl_texture_2D_image,\n        EGL_KHR_gl_texture_3D_image,\n        EGL_KHR_gl_texture_cubemap_image,\n        EGL_KHR_image,\n        EGL_KHR_image_base,\n        EGL_KHR_image_pixmap,\n        EGL_KHR_lock_surface,\n        EGL_KHR_lock_surface2,\n        EGL_KHR_lock_surface3,\n        EGL_KHR_mutable_render_buffer,\n        EGL_KHR_no_config_context,\n        EGL_KHR_partial_update,\n        EGL_KHR_platform_android,\n        EGL_KHR_platform_gbm,\n        EGL_KHR_platform_wayland,\n        EGL_KHR_platform_x11,\n        EGL_KHR_reusable_sync,\n        EGL_KHR_stream,\n        EGL_KHR_stream_attrib,\n        EGL_KHR_stream_consumer_gltexture,\n        EGL_KHR_stream_cross_process_fd,\n        EGL_KHR_stream_fifo,\n        EGL_KHR_stream_producer_aldatalocator,\n        EGL_KHR_stream_producer_eglsurface,\n        EGL_KHR_surfaceless_context,\n        EGL_KHR_swap_buffers_with_damage,\n        EGL_KHR_vg_parent_image,\n        EGL_KHR_wait_sync,\n        EGL_MESA_drm_image,\n        EGL_MESA_image_dma_buf_export,\n        EGL_MESA_platform_gbm,\n        EGL_MESA_platform_surfaceless,\n        EGL_NOK_swap_region,\n        EGL_NOK_swap_region2,\n        EGL_NOK_texture_from_pixmap,\n        EGL_NV_3dvision_surface,\n        EGL_NV_context_priority_realtime,\n        EGL_NV_coverage_sample,\n        EGL_NV_coverage_sample_resolve,\n        EGL_NV_cuda_event,\n        EGL_NV_depth_nonlinear,\n        EGL_NV_device_cuda,\n        EGL_NV_native_query,\n        EGL_NV_post_convert_rounding,\n        EGL_NV_post_sub_buffer,\n        EGL_NV_robustness_video_memory_purge,\n        EGL_NV_stream_consumer_gltexture_yuv,\n        EGL_NV_stream_cross_display,\n        EGL_NV_stream_cross_object,\n        EGL_NV_stream_cross_partition,\n        EGL_NV_stream_cross_process,\n        EGL_NV_stream_cross_system,\n        EGL_NV_stream_fifo_next,\n        EGL_NV_stream_fifo_synchronous,\n        EGL_NV_stream_flush,\n        EGL_NV_stream_frame_limits,\n        EGL_NV_stream_metadata,\n        EGL_NV_stream_remote,\n        EGL_NV_stream_reset,\n        EGL_NV_stream_socket,\n        EGL_NV_stream_socket_inet,\n        EGL_NV_stream_socket_unix,\n        EGL_NV_stream_sync,\n        EGL_NV_sync,\n        EGL_NV_system_time,\n        EGL_TIZEN_image_native_buffer,\n        EGL_TIZEN_image_native_surface\n    Loader: True\n    Local files: False\n    Omit khrplatform: False\n\n    Commandline:\n        --api=\"egl=1.5\" --generator=\"c\" --spec=\"egl\" --extensions=\"EGL_ANDROID_blob_cache,EGL_ANDROID_create_native_client_buffer,EGL_ANDROID_framebuffer_target,EGL_ANDROID_front_buffer_auto_refresh,EGL_ANDROID_get_frame_timestamps,EGL_ANDROID_get_native_client_buffer,EGL_ANDROID_image_native_buffer,EGL_ANDROID_native_fence_sync,EGL_ANDROID_presentation_time,EGL_ANDROID_recordable,EGL_ANGLE_d3d_share_handle_client_buffer,EGL_ANGLE_device_d3d,EGL_ANGLE_query_surface_pointer,EGL_ANGLE_surface_d3d_texture_2d_share_handle,EGL_ANGLE_window_fixed_size,EGL_ARM_implicit_external_sync,EGL_ARM_pixmap_multisample_discard,EGL_EXT_bind_to_front,EGL_EXT_buffer_age,EGL_EXT_client_extensions,EGL_EXT_client_sync,EGL_EXT_compositor,EGL_EXT_create_context_robustness,EGL_EXT_device_base,EGL_EXT_device_drm,EGL_EXT_device_enumeration,EGL_EXT_device_openwf,EGL_EXT_device_query,EGL_EXT_gl_colorspace_bt2020_linear,EGL_EXT_gl_colorspace_bt2020_pq,EGL_EXT_gl_colorspace_display_p3,EGL_EXT_gl_colorspace_display_p3_linear,EGL_EXT_gl_colorspace_display_p3_passthrough,EGL_EXT_gl_colorspace_scrgb,EGL_EXT_gl_colorspace_scrgb_linear,EGL_EXT_image_dma_buf_import,EGL_EXT_image_dma_buf_import_modifiers,EGL_EXT_image_gl_colorspace,EGL_EXT_image_implicit_sync_control,EGL_EXT_multiview_window,EGL_EXT_output_base,EGL_EXT_output_drm,EGL_EXT_output_openwf,EGL_EXT_pixel_format_float,EGL_EXT_platform_base,EGL_EXT_platform_device,EGL_EXT_platform_wayland,EGL_EXT_platform_x11,EGL_EXT_protected_content,EGL_EXT_protected_surface,EGL_EXT_stream_consumer_egloutput,EGL_EXT_surface_CTA861_3_metadata,EGL_EXT_surface_SMPTE2086_metadata,EGL_EXT_swap_buffers_with_damage,EGL_EXT_sync_reuse,EGL_EXT_yuv_surface,EGL_HI_clientpixmap,EGL_HI_colorformats,EGL_IMG_context_priority,EGL_IMG_image_plane_attribs,EGL_KHR_cl_event,EGL_KHR_cl_event2,EGL_KHR_client_get_all_proc_addresses,EGL_KHR_config_attribs,EGL_KHR_context_flush_control,EGL_KHR_create_context,EGL_KHR_create_context_no_error,EGL_KHR_debug,EGL_KHR_display_reference,EGL_KHR_fence_sync,EGL_KHR_get_all_proc_addresses,EGL_KHR_gl_colorspace,EGL_KHR_gl_renderbuffer_image,EGL_KHR_gl_texture_2D_image,EGL_KHR_gl_texture_3D_image,EGL_KHR_gl_texture_cubemap_image,EGL_KHR_image,EGL_KHR_image_base,EGL_KHR_image_pixmap,EGL_KHR_lock_surface,EGL_KHR_lock_surface2,EGL_KHR_lock_surface3,EGL_KHR_mutable_render_buffer,EGL_KHR_no_config_context,EGL_KHR_partial_update,EGL_KHR_platform_android,EGL_KHR_platform_gbm,EGL_KHR_platform_wayland,EGL_KHR_platform_x11,EGL_KHR_reusable_sync,EGL_KHR_stream,EGL_KHR_stream_attrib,EGL_KHR_stream_consumer_gltexture,EGL_KHR_stream_cross_process_fd,EGL_KHR_stream_fifo,EGL_KHR_stream_producer_aldatalocator,EGL_KHR_stream_producer_eglsurface,EGL_KHR_surfaceless_context,EGL_KHR_swap_buffers_with_damage,EGL_KHR_vg_parent_image,EGL_KHR_wait_sync,EGL_MESA_drm_image,EGL_MESA_image_dma_buf_export,EGL_MESA_platform_gbm,EGL_MESA_platform_surfaceless,EGL_NOK_swap_region,EGL_NOK_swap_region2,EGL_NOK_texture_from_pixmap,EGL_NV_3dvision_surface,EGL_NV_context_priority_realtime,EGL_NV_coverage_sample,EGL_NV_coverage_sample_resolve,EGL_NV_cuda_event,EGL_NV_depth_nonlinear,EGL_NV_device_cuda,EGL_NV_native_query,EGL_NV_post_convert_rounding,EGL_NV_post_sub_buffer,EGL_NV_robustness_video_memory_purge,EGL_NV_stream_consumer_gltexture_yuv,EGL_NV_stream_cross_display,EGL_NV_stream_cross_object,EGL_NV_stream_cross_partition,EGL_NV_stream_cross_process,EGL_NV_stream_cross_system,EGL_NV_stream_fifo_next,EGL_NV_stream_fifo_synchronous,EGL_NV_stream_flush,EGL_NV_stream_frame_limits,EGL_NV_stream_metadata,EGL_NV_stream_remote,EGL_NV_stream_reset,EGL_NV_stream_socket,EGL_NV_stream_socket_inet,EGL_NV_stream_socket_unix,EGL_NV_stream_sync,EGL_NV_sync,EGL_NV_system_time,EGL_TIZEN_image_native_buffer,EGL_TIZEN_image_native_surface\"\n    Online:\n        Too many extensions\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <glad/glad_egl.h>\n\nint gladLoadEGL(void) {\n    return gladLoadEGLLoader((GLADloadproc)eglGetProcAddress);\n}\n\nPFNEGLSETBLOBCACHEFUNCSANDROIDPROC glad_eglSetBlobCacheFuncsANDROID;\nPFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC glad_eglCreateNativeClientBufferANDROID;\nPFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC glad_eglGetCompositorTimingSupportedANDROID;\nPFNEGLGETCOMPOSITORTIMINGANDROIDPROC glad_eglGetCompositorTimingANDROID;\nPFNEGLGETNEXTFRAMEIDANDROIDPROC glad_eglGetNextFrameIdANDROID;\nPFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC glad_eglGetFrameTimestampSupportedANDROID;\nPFNEGLGETFRAMETIMESTAMPSANDROIDPROC glad_eglGetFrameTimestampsANDROID;\nPFNEGLGETNATIVECLIENTBUFFERANDROIDPROC glad_eglGetNativeClientBufferANDROID;\nPFNEGLDUPNATIVEFENCEFDANDROIDPROC glad_eglDupNativeFenceFDANDROID;\nPFNEGLPRESENTATIONTIMEANDROIDPROC glad_eglPresentationTimeANDROID;\nPFNEGLQUERYSURFACEPOINTERANGLEPROC glad_eglQuerySurfacePointerANGLE;\nPFNEGLCLIENTSIGNALSYNCEXTPROC glad_eglClientSignalSyncEXT;\nPFNEGLCOMPOSITORSETCONTEXTLISTEXTPROC glad_eglCompositorSetContextListEXT;\nPFNEGLCOMPOSITORSETCONTEXTATTRIBUTESEXTPROC glad_eglCompositorSetContextAttributesEXT;\nPFNEGLCOMPOSITORSETWINDOWLISTEXTPROC glad_eglCompositorSetWindowListEXT;\nPFNEGLCOMPOSITORSETWINDOWATTRIBUTESEXTPROC glad_eglCompositorSetWindowAttributesEXT;\nPFNEGLCOMPOSITORBINDTEXWINDOWEXTPROC glad_eglCompositorBindTexWindowEXT;\nPFNEGLCOMPOSITORSETSIZEEXTPROC glad_eglCompositorSetSizeEXT;\nPFNEGLCOMPOSITORSWAPPOLICYEXTPROC glad_eglCompositorSwapPolicyEXT;\nPFNEGLQUERYDEVICEATTRIBEXTPROC glad_eglQueryDeviceAttribEXT;\nPFNEGLQUERYDEVICESTRINGEXTPROC glad_eglQueryDeviceStringEXT;\nPFNEGLQUERYDEVICESEXTPROC glad_eglQueryDevicesEXT;\nPFNEGLQUERYDISPLAYATTRIBEXTPROC glad_eglQueryDisplayAttribEXT;\nPFNEGLQUERYDMABUFFORMATSEXTPROC glad_eglQueryDmaBufFormatsEXT;\nPFNEGLQUERYDMABUFMODIFIERSEXTPROC glad_eglQueryDmaBufModifiersEXT;\nPFNEGLGETOUTPUTLAYERSEXTPROC glad_eglGetOutputLayersEXT;\nPFNEGLGETOUTPUTPORTSEXTPROC glad_eglGetOutputPortsEXT;\nPFNEGLOUTPUTLAYERATTRIBEXTPROC glad_eglOutputLayerAttribEXT;\nPFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC glad_eglQueryOutputLayerAttribEXT;\nPFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC glad_eglQueryOutputLayerStringEXT;\nPFNEGLOUTPUTPORTATTRIBEXTPROC glad_eglOutputPortAttribEXT;\nPFNEGLQUERYOUTPUTPORTATTRIBEXTPROC glad_eglQueryOutputPortAttribEXT;\nPFNEGLQUERYOUTPUTPORTSTRINGEXTPROC glad_eglQueryOutputPortStringEXT;\nPFNEGLGETPLATFORMDISPLAYEXTPROC glad_eglGetPlatformDisplayEXT;\nPFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC glad_eglCreatePlatformWindowSurfaceEXT;\nPFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC glad_eglCreatePlatformPixmapSurfaceEXT;\nPFNEGLSTREAMCONSUMEROUTPUTEXTPROC glad_eglStreamConsumerOutputEXT;\nPFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC glad_eglSwapBuffersWithDamageEXT;\nPFNEGLUNSIGNALSYNCEXTPROC glad_eglUnsignalSyncEXT;\nPFNEGLCREATEPIXMAPSURFACEHIPROC glad_eglCreatePixmapSurfaceHI;\nPFNEGLCREATESYNC64KHRPROC glad_eglCreateSync64KHR;\nPFNEGLDEBUGMESSAGECONTROLKHRPROC glad_eglDebugMessageControlKHR;\nPFNEGLQUERYDEBUGKHRPROC glad_eglQueryDebugKHR;\nPFNEGLLABELOBJECTKHRPROC glad_eglLabelObjectKHR;\nPFNEGLQUERYDISPLAYATTRIBKHRPROC glad_eglQueryDisplayAttribKHR;\nPFNEGLCREATESYNCKHRPROC glad_eglCreateSyncKHR;\nPFNEGLDESTROYSYNCKHRPROC glad_eglDestroySyncKHR;\nPFNEGLCLIENTWAITSYNCKHRPROC glad_eglClientWaitSyncKHR;\nPFNEGLGETSYNCATTRIBKHRPROC glad_eglGetSyncAttribKHR;\nPFNEGLCREATEIMAGEKHRPROC glad_eglCreateImageKHR;\nPFNEGLDESTROYIMAGEKHRPROC glad_eglDestroyImageKHR;\nPFNEGLLOCKSURFACEKHRPROC glad_eglLockSurfaceKHR;\nPFNEGLUNLOCKSURFACEKHRPROC glad_eglUnlockSurfaceKHR;\nPFNEGLQUERYSURFACE64KHRPROC glad_eglQuerySurface64KHR;\nPFNEGLSETDAMAGEREGIONKHRPROC glad_eglSetDamageRegionKHR;\nPFNEGLSIGNALSYNCKHRPROC glad_eglSignalSyncKHR;\nPFNEGLCREATESTREAMKHRPROC glad_eglCreateStreamKHR;\nPFNEGLDESTROYSTREAMKHRPROC glad_eglDestroyStreamKHR;\nPFNEGLSTREAMATTRIBKHRPROC glad_eglStreamAttribKHR;\nPFNEGLQUERYSTREAMKHRPROC glad_eglQueryStreamKHR;\nPFNEGLQUERYSTREAMU64KHRPROC glad_eglQueryStreamu64KHR;\nPFNEGLCREATESTREAMATTRIBKHRPROC glad_eglCreateStreamAttribKHR;\nPFNEGLSETSTREAMATTRIBKHRPROC glad_eglSetStreamAttribKHR;\nPFNEGLQUERYSTREAMATTRIBKHRPROC glad_eglQueryStreamAttribKHR;\nPFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC glad_eglStreamConsumerAcquireAttribKHR;\nPFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC glad_eglStreamConsumerReleaseAttribKHR;\nPFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC glad_eglStreamConsumerGLTextureExternalKHR;\nPFNEGLSTREAMCONSUMERACQUIREKHRPROC glad_eglStreamConsumerAcquireKHR;\nPFNEGLSTREAMCONSUMERRELEASEKHRPROC glad_eglStreamConsumerReleaseKHR;\nPFNEGLGETSTREAMFILEDESCRIPTORKHRPROC glad_eglGetStreamFileDescriptorKHR;\nPFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC glad_eglCreateStreamFromFileDescriptorKHR;\nPFNEGLQUERYSTREAMTIMEKHRPROC glad_eglQueryStreamTimeKHR;\nPFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC glad_eglCreateStreamProducerSurfaceKHR;\nPFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC glad_eglSwapBuffersWithDamageKHR;\nPFNEGLWAITSYNCKHRPROC glad_eglWaitSyncKHR;\nPFNEGLCREATEDRMIMAGEMESAPROC glad_eglCreateDRMImageMESA;\nPFNEGLEXPORTDRMIMAGEMESAPROC glad_eglExportDRMImageMESA;\nPFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC glad_eglExportDMABUFImageQueryMESA;\nPFNEGLEXPORTDMABUFIMAGEMESAPROC glad_eglExportDMABUFImageMESA;\nPFNEGLSWAPBUFFERSREGIONNOKPROC glad_eglSwapBuffersRegionNOK;\nPFNEGLSWAPBUFFERSREGION2NOKPROC glad_eglSwapBuffersRegion2NOK;\nPFNEGLQUERYNATIVEDISPLAYNVPROC glad_eglQueryNativeDisplayNV;\nPFNEGLQUERYNATIVEWINDOWNVPROC glad_eglQueryNativeWindowNV;\nPFNEGLQUERYNATIVEPIXMAPNVPROC glad_eglQueryNativePixmapNV;\nPFNEGLPOSTSUBBUFFERNVPROC glad_eglPostSubBufferNV;\nPFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC glad_eglStreamConsumerGLTextureExternalAttribsNV;\nPFNEGLSTREAMFLUSHNVPROC glad_eglStreamFlushNV;\nPFNEGLQUERYDISPLAYATTRIBNVPROC glad_eglQueryDisplayAttribNV;\nPFNEGLSETSTREAMMETADATANVPROC glad_eglSetStreamMetadataNV;\nPFNEGLQUERYSTREAMMETADATANVPROC glad_eglQueryStreamMetadataNV;\nPFNEGLRESETSTREAMNVPROC glad_eglResetStreamNV;\nPFNEGLCREATESTREAMSYNCNVPROC glad_eglCreateStreamSyncNV;\nPFNEGLCREATEFENCESYNCNVPROC glad_eglCreateFenceSyncNV;\nPFNEGLDESTROYSYNCNVPROC glad_eglDestroySyncNV;\nPFNEGLFENCENVPROC glad_eglFenceNV;\nPFNEGLCLIENTWAITSYNCNVPROC glad_eglClientWaitSyncNV;\nPFNEGLSIGNALSYNCNVPROC glad_eglSignalSyncNV;\nPFNEGLGETSYNCATTRIBNVPROC glad_eglGetSyncAttribNV;\nPFNEGLGETSYSTEMTIMEFREQUENCYNVPROC glad_eglGetSystemTimeFrequencyNV;\nPFNEGLGETSYSTEMTIMENVPROC glad_eglGetSystemTimeNV;\nstatic void load_EGL_ANDROID_blob_cache(GLADloadproc load) {\n\tglad_eglSetBlobCacheFuncsANDROID = (PFNEGLSETBLOBCACHEFUNCSANDROIDPROC)load(\"eglSetBlobCacheFuncsANDROID\");\n}\nstatic void load_EGL_ANDROID_create_native_client_buffer(GLADloadproc load) {\n\tglad_eglCreateNativeClientBufferANDROID = (PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC)load(\"eglCreateNativeClientBufferANDROID\");\n}\nstatic void load_EGL_ANDROID_get_frame_timestamps(GLADloadproc load) {\n\tglad_eglGetCompositorTimingSupportedANDROID = (PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC)load(\"eglGetCompositorTimingSupportedANDROID\");\n\tglad_eglGetCompositorTimingANDROID = (PFNEGLGETCOMPOSITORTIMINGANDROIDPROC)load(\"eglGetCompositorTimingANDROID\");\n\tglad_eglGetNextFrameIdANDROID = (PFNEGLGETNEXTFRAMEIDANDROIDPROC)load(\"eglGetNextFrameIdANDROID\");\n\tglad_eglGetFrameTimestampSupportedANDROID = (PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC)load(\"eglGetFrameTimestampSupportedANDROID\");\n\tglad_eglGetFrameTimestampsANDROID = (PFNEGLGETFRAMETIMESTAMPSANDROIDPROC)load(\"eglGetFrameTimestampsANDROID\");\n}\nstatic void load_EGL_ANDROID_get_native_client_buffer(GLADloadproc load) {\n\tglad_eglGetNativeClientBufferANDROID = (PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC)load(\"eglGetNativeClientBufferANDROID\");\n}\nstatic void load_EGL_ANDROID_native_fence_sync(GLADloadproc load) {\n\tglad_eglDupNativeFenceFDANDROID = (PFNEGLDUPNATIVEFENCEFDANDROIDPROC)load(\"eglDupNativeFenceFDANDROID\");\n}\nstatic void load_EGL_ANDROID_presentation_time(GLADloadproc load) {\n\tglad_eglPresentationTimeANDROID = (PFNEGLPRESENTATIONTIMEANDROIDPROC)load(\"eglPresentationTimeANDROID\");\n}\nstatic void load_EGL_ANGLE_query_surface_pointer(GLADloadproc load) {\n\tglad_eglQuerySurfacePointerANGLE = (PFNEGLQUERYSURFACEPOINTERANGLEPROC)load(\"eglQuerySurfacePointerANGLE\");\n}\nstatic void load_EGL_EXT_client_sync(GLADloadproc load) {\n\tglad_eglClientSignalSyncEXT = (PFNEGLCLIENTSIGNALSYNCEXTPROC)load(\"eglClientSignalSyncEXT\");\n}\nstatic void load_EGL_EXT_compositor(GLADloadproc load) {\n\tglad_eglCompositorSetContextListEXT = (PFNEGLCOMPOSITORSETCONTEXTLISTEXTPROC)load(\"eglCompositorSetContextListEXT\");\n\tglad_eglCompositorSetContextAttributesEXT = (PFNEGLCOMPOSITORSETCONTEXTATTRIBUTESEXTPROC)load(\"eglCompositorSetContextAttributesEXT\");\n\tglad_eglCompositorSetWindowListEXT = (PFNEGLCOMPOSITORSETWINDOWLISTEXTPROC)load(\"eglCompositorSetWindowListEXT\");\n\tglad_eglCompositorSetWindowAttributesEXT = (PFNEGLCOMPOSITORSETWINDOWATTRIBUTESEXTPROC)load(\"eglCompositorSetWindowAttributesEXT\");\n\tglad_eglCompositorBindTexWindowEXT = (PFNEGLCOMPOSITORBINDTEXWINDOWEXTPROC)load(\"eglCompositorBindTexWindowEXT\");\n\tglad_eglCompositorSetSizeEXT = (PFNEGLCOMPOSITORSETSIZEEXTPROC)load(\"eglCompositorSetSizeEXT\");\n\tglad_eglCompositorSwapPolicyEXT = (PFNEGLCOMPOSITORSWAPPOLICYEXTPROC)load(\"eglCompositorSwapPolicyEXT\");\n}\nstatic void load_EGL_EXT_device_base(GLADloadproc load) {\n\tglad_eglQueryDeviceAttribEXT = (PFNEGLQUERYDEVICEATTRIBEXTPROC)load(\"eglQueryDeviceAttribEXT\");\n\tglad_eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC)load(\"eglQueryDeviceStringEXT\");\n\tglad_eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)load(\"eglQueryDevicesEXT\");\n\tglad_eglQueryDisplayAttribEXT = (PFNEGLQUERYDISPLAYATTRIBEXTPROC)load(\"eglQueryDisplayAttribEXT\");\n}\nstatic void load_EGL_EXT_device_enumeration(GLADloadproc load) {\n\tglad_eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)load(\"eglQueryDevicesEXT\");\n}\nstatic void load_EGL_EXT_device_query(GLADloadproc load) {\n\tglad_eglQueryDeviceAttribEXT = (PFNEGLQUERYDEVICEATTRIBEXTPROC)load(\"eglQueryDeviceAttribEXT\");\n\tglad_eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC)load(\"eglQueryDeviceStringEXT\");\n\tglad_eglQueryDisplayAttribEXT = (PFNEGLQUERYDISPLAYATTRIBEXTPROC)load(\"eglQueryDisplayAttribEXT\");\n}\nstatic void load_EGL_EXT_image_dma_buf_import_modifiers(GLADloadproc load) {\n\tglad_eglQueryDmaBufFormatsEXT = (PFNEGLQUERYDMABUFFORMATSEXTPROC)load(\"eglQueryDmaBufFormatsEXT\");\n\tglad_eglQueryDmaBufModifiersEXT = (PFNEGLQUERYDMABUFMODIFIERSEXTPROC)load(\"eglQueryDmaBufModifiersEXT\");\n}\nstatic void load_EGL_EXT_output_base(GLADloadproc load) {\n\tglad_eglGetOutputLayersEXT = (PFNEGLGETOUTPUTLAYERSEXTPROC)load(\"eglGetOutputLayersEXT\");\n\tglad_eglGetOutputPortsEXT = (PFNEGLGETOUTPUTPORTSEXTPROC)load(\"eglGetOutputPortsEXT\");\n\tglad_eglOutputLayerAttribEXT = (PFNEGLOUTPUTLAYERATTRIBEXTPROC)load(\"eglOutputLayerAttribEXT\");\n\tglad_eglQueryOutputLayerAttribEXT = (PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC)load(\"eglQueryOutputLayerAttribEXT\");\n\tglad_eglQueryOutputLayerStringEXT = (PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC)load(\"eglQueryOutputLayerStringEXT\");\n\tglad_eglOutputPortAttribEXT = (PFNEGLOUTPUTPORTATTRIBEXTPROC)load(\"eglOutputPortAttribEXT\");\n\tglad_eglQueryOutputPortAttribEXT = (PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC)load(\"eglQueryOutputPortAttribEXT\");\n\tglad_eglQueryOutputPortStringEXT = (PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC)load(\"eglQueryOutputPortStringEXT\");\n}\nstatic void load_EGL_EXT_platform_base(GLADloadproc load) {\n\tglad_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)load(\"eglGetPlatformDisplayEXT\");\n\tglad_eglCreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)load(\"eglCreatePlatformWindowSurfaceEXT\");\n\tglad_eglCreatePlatformPixmapSurfaceEXT = (PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC)load(\"eglCreatePlatformPixmapSurfaceEXT\");\n}\nstatic void load_EGL_EXT_stream_consumer_egloutput(GLADloadproc load) {\n\tglad_eglStreamConsumerOutputEXT = (PFNEGLSTREAMCONSUMEROUTPUTEXTPROC)load(\"eglStreamConsumerOutputEXT\");\n}\nstatic void load_EGL_EXT_swap_buffers_with_damage(GLADloadproc load) {\n\tglad_eglSwapBuffersWithDamageEXT = (PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)load(\"eglSwapBuffersWithDamageEXT\");\n}\nstatic void load_EGL_EXT_sync_reuse(GLADloadproc load) {\n\tglad_eglUnsignalSyncEXT = (PFNEGLUNSIGNALSYNCEXTPROC)load(\"eglUnsignalSyncEXT\");\n}\nstatic void load_EGL_HI_clientpixmap(GLADloadproc load) {\n\tglad_eglCreatePixmapSurfaceHI = (PFNEGLCREATEPIXMAPSURFACEHIPROC)load(\"eglCreatePixmapSurfaceHI\");\n}\nstatic void load_EGL_KHR_cl_event2(GLADloadproc load) {\n\tglad_eglCreateSync64KHR = (PFNEGLCREATESYNC64KHRPROC)load(\"eglCreateSync64KHR\");\n}\nstatic void load_EGL_KHR_debug(GLADloadproc load) {\n\tglad_eglDebugMessageControlKHR = (PFNEGLDEBUGMESSAGECONTROLKHRPROC)load(\"eglDebugMessageControlKHR\");\n\tglad_eglQueryDebugKHR = (PFNEGLQUERYDEBUGKHRPROC)load(\"eglQueryDebugKHR\");\n\tglad_eglLabelObjectKHR = (PFNEGLLABELOBJECTKHRPROC)load(\"eglLabelObjectKHR\");\n}\nstatic void load_EGL_KHR_display_reference(GLADloadproc load) {\n\tglad_eglQueryDisplayAttribKHR = (PFNEGLQUERYDISPLAYATTRIBKHRPROC)load(\"eglQueryDisplayAttribKHR\");\n}\nstatic void load_EGL_KHR_fence_sync(GLADloadproc load) {\n\tglad_eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC)load(\"eglCreateSyncKHR\");\n\tglad_eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)load(\"eglDestroySyncKHR\");\n\tglad_eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)load(\"eglClientWaitSyncKHR\");\n\tglad_eglGetSyncAttribKHR = (PFNEGLGETSYNCATTRIBKHRPROC)load(\"eglGetSyncAttribKHR\");\n}\nstatic void load_EGL_KHR_image(GLADloadproc load) {\n\tglad_eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)load(\"eglCreateImageKHR\");\n\tglad_eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)load(\"eglDestroyImageKHR\");\n}\nstatic void load_EGL_KHR_image_base(GLADloadproc load) {\n\tglad_eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)load(\"eglCreateImageKHR\");\n\tglad_eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)load(\"eglDestroyImageKHR\");\n}\nstatic void load_EGL_KHR_lock_surface(GLADloadproc load) {\n\tglad_eglLockSurfaceKHR = (PFNEGLLOCKSURFACEKHRPROC)load(\"eglLockSurfaceKHR\");\n\tglad_eglUnlockSurfaceKHR = (PFNEGLUNLOCKSURFACEKHRPROC)load(\"eglUnlockSurfaceKHR\");\n}\nstatic void load_EGL_KHR_lock_surface3(GLADloadproc load) {\n\tglad_eglLockSurfaceKHR = (PFNEGLLOCKSURFACEKHRPROC)load(\"eglLockSurfaceKHR\");\n\tglad_eglUnlockSurfaceKHR = (PFNEGLUNLOCKSURFACEKHRPROC)load(\"eglUnlockSurfaceKHR\");\n\tglad_eglQuerySurface64KHR = (PFNEGLQUERYSURFACE64KHRPROC)load(\"eglQuerySurface64KHR\");\n}\nstatic void load_EGL_KHR_partial_update(GLADloadproc load) {\n\tglad_eglSetDamageRegionKHR = (PFNEGLSETDAMAGEREGIONKHRPROC)load(\"eglSetDamageRegionKHR\");\n}\nstatic void load_EGL_KHR_reusable_sync(GLADloadproc load) {\n\tglad_eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC)load(\"eglCreateSyncKHR\");\n\tglad_eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)load(\"eglDestroySyncKHR\");\n\tglad_eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)load(\"eglClientWaitSyncKHR\");\n\tglad_eglSignalSyncKHR = (PFNEGLSIGNALSYNCKHRPROC)load(\"eglSignalSyncKHR\");\n\tglad_eglGetSyncAttribKHR = (PFNEGLGETSYNCATTRIBKHRPROC)load(\"eglGetSyncAttribKHR\");\n}\nstatic void load_EGL_KHR_stream(GLADloadproc load) {\n\tglad_eglCreateStreamKHR = (PFNEGLCREATESTREAMKHRPROC)load(\"eglCreateStreamKHR\");\n\tglad_eglDestroyStreamKHR = (PFNEGLDESTROYSTREAMKHRPROC)load(\"eglDestroyStreamKHR\");\n\tglad_eglStreamAttribKHR = (PFNEGLSTREAMATTRIBKHRPROC)load(\"eglStreamAttribKHR\");\n\tglad_eglQueryStreamKHR = (PFNEGLQUERYSTREAMKHRPROC)load(\"eglQueryStreamKHR\");\n\tglad_eglQueryStreamu64KHR = (PFNEGLQUERYSTREAMU64KHRPROC)load(\"eglQueryStreamu64KHR\");\n}\nstatic void load_EGL_KHR_stream_attrib(GLADloadproc load) {\n\tglad_eglCreateStreamAttribKHR = (PFNEGLCREATESTREAMATTRIBKHRPROC)load(\"eglCreateStreamAttribKHR\");\n\tglad_eglSetStreamAttribKHR = (PFNEGLSETSTREAMATTRIBKHRPROC)load(\"eglSetStreamAttribKHR\");\n\tglad_eglQueryStreamAttribKHR = (PFNEGLQUERYSTREAMATTRIBKHRPROC)load(\"eglQueryStreamAttribKHR\");\n\tglad_eglStreamConsumerAcquireAttribKHR = (PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC)load(\"eglStreamConsumerAcquireAttribKHR\");\n\tglad_eglStreamConsumerReleaseAttribKHR = (PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC)load(\"eglStreamConsumerReleaseAttribKHR\");\n}\nstatic void load_EGL_KHR_stream_consumer_gltexture(GLADloadproc load) {\n\tglad_eglStreamConsumerGLTextureExternalKHR = (PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC)load(\"eglStreamConsumerGLTextureExternalKHR\");\n\tglad_eglStreamConsumerAcquireKHR = (PFNEGLSTREAMCONSUMERACQUIREKHRPROC)load(\"eglStreamConsumerAcquireKHR\");\n\tglad_eglStreamConsumerReleaseKHR = (PFNEGLSTREAMCONSUMERRELEASEKHRPROC)load(\"eglStreamConsumerReleaseKHR\");\n}\nstatic void load_EGL_KHR_stream_cross_process_fd(GLADloadproc load) {\n\tglad_eglGetStreamFileDescriptorKHR = (PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC)load(\"eglGetStreamFileDescriptorKHR\");\n\tglad_eglCreateStreamFromFileDescriptorKHR = (PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC)load(\"eglCreateStreamFromFileDescriptorKHR\");\n}\nstatic void load_EGL_KHR_stream_fifo(GLADloadproc load) {\n\tglad_eglQueryStreamTimeKHR = (PFNEGLQUERYSTREAMTIMEKHRPROC)load(\"eglQueryStreamTimeKHR\");\n}\nstatic void load_EGL_KHR_stream_producer_eglsurface(GLADloadproc load) {\n\tglad_eglCreateStreamProducerSurfaceKHR = (PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC)load(\"eglCreateStreamProducerSurfaceKHR\");\n}\nstatic void load_EGL_KHR_swap_buffers_with_damage(GLADloadproc load) {\n\tglad_eglSwapBuffersWithDamageKHR = (PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC)load(\"eglSwapBuffersWithDamageKHR\");\n}\nstatic void load_EGL_KHR_wait_sync(GLADloadproc load) {\n\tglad_eglWaitSyncKHR = (PFNEGLWAITSYNCKHRPROC)load(\"eglWaitSyncKHR\");\n}\nstatic void load_EGL_MESA_drm_image(GLADloadproc load) {\n\tglad_eglCreateDRMImageMESA = (PFNEGLCREATEDRMIMAGEMESAPROC)load(\"eglCreateDRMImageMESA\");\n\tglad_eglExportDRMImageMESA = (PFNEGLEXPORTDRMIMAGEMESAPROC)load(\"eglExportDRMImageMESA\");\n}\nstatic void load_EGL_MESA_image_dma_buf_export(GLADloadproc load) {\n\tglad_eglExportDMABUFImageQueryMESA = (PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC)load(\"eglExportDMABUFImageQueryMESA\");\n\tglad_eglExportDMABUFImageMESA = (PFNEGLEXPORTDMABUFIMAGEMESAPROC)load(\"eglExportDMABUFImageMESA\");\n}\nstatic void load_EGL_NOK_swap_region(GLADloadproc load) {\n\tglad_eglSwapBuffersRegionNOK = (PFNEGLSWAPBUFFERSREGIONNOKPROC)load(\"eglSwapBuffersRegionNOK\");\n}\nstatic void load_EGL_NOK_swap_region2(GLADloadproc load) {\n\tglad_eglSwapBuffersRegion2NOK = (PFNEGLSWAPBUFFERSREGION2NOKPROC)load(\"eglSwapBuffersRegion2NOK\");\n}\nstatic void load_EGL_NV_native_query(GLADloadproc load) {\n\tglad_eglQueryNativeDisplayNV = (PFNEGLQUERYNATIVEDISPLAYNVPROC)load(\"eglQueryNativeDisplayNV\");\n\tglad_eglQueryNativeWindowNV = (PFNEGLQUERYNATIVEWINDOWNVPROC)load(\"eglQueryNativeWindowNV\");\n\tglad_eglQueryNativePixmapNV = (PFNEGLQUERYNATIVEPIXMAPNVPROC)load(\"eglQueryNativePixmapNV\");\n}\nstatic void load_EGL_NV_post_sub_buffer(GLADloadproc load) {\n\tglad_eglPostSubBufferNV = (PFNEGLPOSTSUBBUFFERNVPROC)load(\"eglPostSubBufferNV\");\n}\nstatic void load_EGL_NV_stream_consumer_gltexture_yuv(GLADloadproc load) {\n\tglad_eglStreamConsumerGLTextureExternalAttribsNV = (PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC)load(\"eglStreamConsumerGLTextureExternalAttribsNV\");\n}\nstatic void load_EGL_NV_stream_flush(GLADloadproc load) {\n\tglad_eglStreamFlushNV = (PFNEGLSTREAMFLUSHNVPROC)load(\"eglStreamFlushNV\");\n}\nstatic void load_EGL_NV_stream_metadata(GLADloadproc load) {\n\tglad_eglQueryDisplayAttribNV = (PFNEGLQUERYDISPLAYATTRIBNVPROC)load(\"eglQueryDisplayAttribNV\");\n\tglad_eglSetStreamMetadataNV = (PFNEGLSETSTREAMMETADATANVPROC)load(\"eglSetStreamMetadataNV\");\n\tglad_eglQueryStreamMetadataNV = (PFNEGLQUERYSTREAMMETADATANVPROC)load(\"eglQueryStreamMetadataNV\");\n}\nstatic void load_EGL_NV_stream_reset(GLADloadproc load) {\n\tglad_eglResetStreamNV = (PFNEGLRESETSTREAMNVPROC)load(\"eglResetStreamNV\");\n}\nstatic void load_EGL_NV_stream_sync(GLADloadproc load) {\n\tglad_eglCreateStreamSyncNV = (PFNEGLCREATESTREAMSYNCNVPROC)load(\"eglCreateStreamSyncNV\");\n}\nstatic void load_EGL_NV_sync(GLADloadproc load) {\n\tglad_eglCreateFenceSyncNV = (PFNEGLCREATEFENCESYNCNVPROC)load(\"eglCreateFenceSyncNV\");\n\tglad_eglDestroySyncNV = (PFNEGLDESTROYSYNCNVPROC)load(\"eglDestroySyncNV\");\n\tglad_eglFenceNV = (PFNEGLFENCENVPROC)load(\"eglFenceNV\");\n\tglad_eglClientWaitSyncNV = (PFNEGLCLIENTWAITSYNCNVPROC)load(\"eglClientWaitSyncNV\");\n\tglad_eglSignalSyncNV = (PFNEGLSIGNALSYNCNVPROC)load(\"eglSignalSyncNV\");\n\tglad_eglGetSyncAttribNV = (PFNEGLGETSYNCATTRIBNVPROC)load(\"eglGetSyncAttribNV\");\n}\nstatic void load_EGL_NV_system_time(GLADloadproc load) {\n\tglad_eglGetSystemTimeFrequencyNV = (PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)load(\"eglGetSystemTimeFrequencyNV\");\n\tglad_eglGetSystemTimeNV = (PFNEGLGETSYSTEMTIMENVPROC)load(\"eglGetSystemTimeNV\");\n}\nstatic int find_extensionsEGL(void) {\n\treturn 1;\n}\n\nstatic void find_coreEGL(void) {\n}\n\nint gladLoadEGLLoader(GLADloadproc load) {\n\t(void) load;\n\tfind_coreEGL();\n\n\tif (!find_extensionsEGL()) return 0;\n\tload_EGL_ANDROID_blob_cache(load);\n\tload_EGL_ANDROID_create_native_client_buffer(load);\n\tload_EGL_ANDROID_get_frame_timestamps(load);\n\tload_EGL_ANDROID_get_native_client_buffer(load);\n\tload_EGL_ANDROID_native_fence_sync(load);\n\tload_EGL_ANDROID_presentation_time(load);\n\tload_EGL_ANGLE_query_surface_pointer(load);\n\tload_EGL_EXT_client_sync(load);\n\tload_EGL_EXT_compositor(load);\n\tload_EGL_EXT_device_base(load);\n\tload_EGL_EXT_device_enumeration(load);\n\tload_EGL_EXT_device_query(load);\n\tload_EGL_EXT_image_dma_buf_import_modifiers(load);\n\tload_EGL_EXT_output_base(load);\n\tload_EGL_EXT_platform_base(load);\n\tload_EGL_EXT_stream_consumer_egloutput(load);\n\tload_EGL_EXT_swap_buffers_with_damage(load);\n\tload_EGL_EXT_sync_reuse(load);\n\tload_EGL_HI_clientpixmap(load);\n\tload_EGL_KHR_cl_event2(load);\n\tload_EGL_KHR_debug(load);\n\tload_EGL_KHR_display_reference(load);\n\tload_EGL_KHR_fence_sync(load);\n\tload_EGL_KHR_image(load);\n\tload_EGL_KHR_image_base(load);\n\tload_EGL_KHR_lock_surface(load);\n\tload_EGL_KHR_lock_surface3(load);\n\tload_EGL_KHR_partial_update(load);\n\tload_EGL_KHR_reusable_sync(load);\n\tload_EGL_KHR_stream(load);\n\tload_EGL_KHR_stream_attrib(load);\n\tload_EGL_KHR_stream_consumer_gltexture(load);\n\tload_EGL_KHR_stream_cross_process_fd(load);\n\tload_EGL_KHR_stream_fifo(load);\n\tload_EGL_KHR_stream_producer_eglsurface(load);\n\tload_EGL_KHR_swap_buffers_with_damage(load);\n\tload_EGL_KHR_wait_sync(load);\n\tload_EGL_MESA_drm_image(load);\n\tload_EGL_MESA_image_dma_buf_export(load);\n\tload_EGL_NOK_swap_region(load);\n\tload_EGL_NOK_swap_region2(load);\n\tload_EGL_NV_native_query(load);\n\tload_EGL_NV_post_sub_buffer(load);\n\tload_EGL_NV_stream_consumer_gltexture_yuv(load);\n\tload_EGL_NV_stream_flush(load);\n\tload_EGL_NV_stream_metadata(load);\n\tload_EGL_NV_stream_reset(load);\n\tload_EGL_NV_stream_sync(load);\n\tload_EGL_NV_sync(load);\n\tload_EGL_NV_system_time(load);\n\treturn 1;\n}\n\n"
  },
  {
    "path": "src/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\nproject(megaverse)\n\nadd_definitions(-DGLM_ENABLE_EXPERIMENTAL)\n\noption(BUILD_GUI_APPS \"Whether to build apps that require GUI (things like SDL2)\" ON)\n\nset(CMAKE_POSITION_INDEPENDENT_CODE ON)\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nset(CMAKE_MODULE_PATH \"${PROJECT_SOURCE_DIR}/cmake/modules/\" ${CMAKE_MODULE_PATH})\n\ninclude(cmake/util.cmake)\ncommon_settings()\n\nadd_subdirectory(3rdparty)\n\nadd_compile_options(-Wall -Wextra -Wdelete-non-virtual-dtor -pedantic -Werror)\nadd_subdirectory(libs)\n\nadd_subdirectory(apps)\nadd_subdirectory(examples)\nadd_subdirectory(test)\n"
  },
  {
    "path": "src/apps/CMakeLists.txt",
    "content": "find_package(Corrade REQUIRED Main)\nset(MAGNUM_DEPENDENCIES\n        Corrade::Main\n        Magnum::GL\n        Magnum::Magnum\n        Magnum::MeshTools\n        Magnum::Primitives\n        Magnum::SceneGraph\n        Magnum::Shaders\n)\n\nif (BUILD_GUI_APPS)\n    set(VIEWER_APP_SOURCES viewer_app.cpp viewer_args.cpp)\n    add_app_default(viewer_app \"${VIEWER_APP_SOURCES}\")  # list of sources gotta be in quites\n    target_link_libraries(viewer_app PRIVATE scenarios viewer Magnum::Application)\nendif()\n\nfind_package(ZLIB)\n\nset(MEGAVERSE_TEST_APP_SOURCES megaverse_test_app.cpp viewer_args.cpp)\nadd_app_default(megaverse_test_app \"${MEGAVERSE_TEST_APP_SOURCES}\")\ntarget_link_libraries(megaverse_test_app PRIVATE scenarios magnum_rendering ${MAGNUM_DEPENDENCIES} ${OpenCV_LIBS})\n\nif (ZLIB_FOUND)\n    target_link_libraries(megaverse_test_app PRIVATE ${ZLIB_LIBRARIES})\nendif ()\n\nif (NOT CORRADE_TARGET_APPLE)\n    target_link_libraries(megaverse_test_app PRIVATE v4r_rendering)\nendif ()\n\n# Make the executable a default target to build & run in Visual Studio\nset_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT viewer)\n\n\nadd_app_default(mazegen mazegen.cpp)\ntarget_link_libraries(mazegen PRIVATE mazes)\n"
  },
  {
    "path": "src/apps/mazegen.cpp",
    "content": "#include <mazes/breadthfirstsearch.h>\n#include <mazes/circularhexagonmaze.h>\n#include <mazes/circularmaze.h>\n#include <mazes/depthfirstsearch.h>\n#include <mazes/hexagonalmaze.h>\n#include <mazes/honeycombmaze.h>\n#include <mazes/kruskal.h>\n#include <mazes/looperasedrandomwalk.h>\n#include <mazes/prim.h>\n#include <mazes/rectangularmaze.h>\n#include <mazes/usermaze.h>\n#include <cstring>\n#include <iostream>\n#include <map>\n#include <string>\n\nvoid usage(std::ostream &out) {\n  out << \"Usage: mazegen [--help] [-m <maze type>] [-a <algorithm type>]\"\n      << std::endl;\n  out << \"               [-s <size> | -w <width> -h <height>]\" << std::endl;\n  out << \"               [-t <output type>] [-o <output prefix>]\" << std::endl;\n  out << \"               [-f <graph description file (for m=5)>]\" << std::endl;\n\n  out << std::endl;\n  out << \"Optional arguments\" << std::endl;\n  out << \"  --help  \"\n      << \"Show this message and exit\" << std::endl;\n  out << \"  -m      \"\n      << \"Maze type\" << std::endl;\n  out << \"          \"\n      << \"0: Rectangular (default)\" << std::endl;\n  out << \"          \"\n      << \"1: Hexagonal (triangular lattice)\" << std::endl;\n  out << \"          \"\n      << \"2: Honeycomb\" << std::endl;\n  out << \"          \"\n      << \"3: Circular\" << std::endl;\n  out << \"          \"\n      << \"4: Circular (triangular lattice)\" << std::endl;\n  out << \"          \"\n      << \"5: User defined graph\" << std::endl;\n  out << \"  -a      \"\n      << \"Algorithm type\" << std::endl;\n  out << \"          \"\n      << \"0: Kruskal's algorithm (default)\" << std::endl;\n  out << \"          \"\n      << \"1: Depth-first search\" << std::endl;\n  out << \"          \"\n      << \"2: Breadth-first search\" << std::endl;\n  out << \"          \"\n      << \"3: Loop-erased random walk\" << std::endl;\n  out << \"          \"\n      << \"4: Prim's algorithm\" << std::endl;\n  out << \"  -s      \"\n      << \"Size (non-rectangular mazes, default: 20)\" << std::endl;\n  out << \"  -w,-h   \"\n      << \"Width and height (rectangular maze, default: 20)\" << std::endl;\n  out << \"  -t      \"\n      << \"Output type\" << std::endl;\n  out << \"          \"\n      << \"0: svg output (default)\" << std::endl;\n  out << \"          \"\n      << \"1: png output using gnuplot (.plt) intermediate \" << std::endl;\n  out << \"  -o      \"\n      << \"Prefix for .svg, .plt and .png outputs (default: maze)\" << std::endl;\n}\n\nint main(int argc, char *argv[]) {\n  std::string outputprefix = \"maze\", infile = \"\";\n  std::map<std::string, int> optionmap{{\"-m\", 0},  {\"-a\", 0},     {\"-s\", 20},\n                                       {\"-w\", 20}, {\"-h\", 20},    {\"-o\", 0},\n                                       {\"-f\", 0},  {\"--help\", 0}, {\"-t\", 0}};\n\n  for (int i = 1; i < argc; i++) {\n    if (optionmap.find(argv[i]) == optionmap.end()) {\n      std::cerr << \"Unknown argument \" << argv[i] << \"\\n\";\n      usage(std::cerr);\n      return 1;\n    }\n\n    if (strcmp(\"-o\", argv[i]) == 0) {\n      if (i + 1 == argc) {\n        std::cerr << \"Missing output prefix\" << std::endl;\n        usage(std::cerr);\n        return 1;\n      }\n      outputprefix = argv[++i];\n      continue;\n    } else if (strcmp(\"-f\", argv[i]) == 0) {\n      if (i + 1 == argc) {\n        std::cerr << \"Missing maze input file\" << std::endl;\n        usage(std::cerr);\n        return 1;\n      }\n      infile = argv[++i];\n      continue;\n    } else if (strcmp(\"--help\", argv[i]) == 0) {\n      usage(std::cout);\n      return 0;\n    }\n\n    if (i + 1 == argc) {\n      std::cerr << \"Missing option for argument \" << argv[i] << std::endl;\n      usage(std::cerr);\n      return 1;\n    }\n    int x;\n    try {\n      x = std::stoi(argv[i + 1]);\n    } catch (...) {\n      std::cerr << \"Invalid argument \" << argv[i + 1] << \" for option \"\n                << argv[i] << \"\\n\";\n      usage(std::cerr);\n      return 1;\n    }\n    optionmap[argv[i++]] = x;\n  }\n\n  Maze *maze;\n  SpanningtreeAlgorithm *algorithm;\n\n  switch (optionmap[\"-m\"]) {\n    case 0:\n      if (optionmap[\"-w\"] < 1 or optionmap[\"-h\"] < 1) {\n        std::cerr << \"Invalide size \" << optionmap[\"-w\"] << \"x\"\n                  << optionmap[\"-h\"] << \" for rectangular maze\\n\";\n        usage(std::cerr);\n        return 1;\n      }\n      std::cout << \"Rectangular maze of size \" << optionmap[\"-w\"] << \"x\"\n                << optionmap[\"-h\"] << \"\\n\";\n      maze = new RectangularMaze(optionmap[\"-w\"], optionmap[\"-h\"]);\n      break;\n\n    case 1:\n      if (optionmap[\"-s\"] < 1) {\n        std::cerr << \"Invalide size \" << optionmap[\"-s\"]\n                  << \" for hexagonal maze with triangular lattice\\n\";\n        usage(std::cerr);\n        return 1;\n      }\n      std::cout << \"Hexagonal maze with triangular lattice of size \"\n                << optionmap[\"-s\"] << \"\\n\";\n      maze = new HexagonalMaze(optionmap[\"-s\"]);\n      break;\n\n    case 2:\n      if (optionmap[\"-s\"] < 1) {\n        std::cerr << \"Invalide size \" << optionmap[\"-s\"]\n                  << \" for honeycomb maze\\n\";\n        usage(std::cerr);\n        return 1;\n      }\n      std::cout << \"Honeycomb maze of size \" << optionmap[\"-s\"] << \"\\n\";\n      maze = new HoneyCombMaze(optionmap[\"-s\"]);\n      break;\n\n    case 3:\n      if (optionmap[\"-s\"] < 1) {\n        std::cerr << \"Invalide size \" << optionmap[\"-s\"]\n                  << \" for circular maze\\n\";\n        usage(std::cerr);\n        return 1;\n      }\n      std::cout << \"Circular maze of size \" << optionmap[\"-s\"] << \"\\n\";\n      maze = new CircularMaze(optionmap[\"-s\"]);\n      break;\n\n    case 4:\n      if (optionmap[\"-s\"] < 1) {\n        std::cerr << \"Invalide size \" << optionmap[\"-s\"]\n                  << \" for circular maze with triangular lattice\\n\";\n        usage(std::cerr);\n        return 1;\n      }\n      std::cout << \"Circular maze with triangular lattice of size \"\n                << optionmap[\"-s\"] << \"\\n\";\n      maze = new CircularHexagonMaze(optionmap[\"-s\"]);\n      break;\n\n    case 5:\n      if (infile == \"\") {\n        std::cerr\n            << \"Graph description file not provided for user-defined graph\\n\";\n        usage(std::cerr);\n        return 1;\n      }\n      std::cout << \"User-defined graph\\n\";\n      maze = new UserMaze(infile);\n      break;\n\n    default:\n      std::cerr << \"Unknown maze type \" << optionmap[\"-m\"];\n      usage(std::cerr);\n      return 1;\n  }\n\n  switch (optionmap[\"-a\"]) {\n    case 0:\n      std::cout << \"Maze generation using Kruskal's algorithm\\n\";\n      algorithm = new Kruskal;\n      break;\n\n    case 1:\n      std::cout << \"Maze generation using Depth-first search\\n\";\n      algorithm = new DepthFirstSearch;\n      break;\n\n    case 2:\n      std::cout << \"Maze generation using Breadth-first search\\n\";\n      algorithm = new BreadthFirstSearch;\n      break;\n\n    case 3:\n      std::cout << \"Maze generation using Loop-erased random walk\\n\";\n      algorithm = new LoopErasedRandomWalk;\n      break;\n\n    case 4:\n      std::cout << \"Maze generation using Prim's algorithm\\n\";\n      algorithm = new Prim;\n      break;\n\n    default:\n      std::cerr << \"Unknown algorithm type \" << optionmap[\"-a\"];\n      usage(std::cerr);\n      return 1;\n  }\n\n  if (optionmap[\"-t\"] < 0 or optionmap[\"-t\"] > 1) {\n    std::cerr << \"Unknown output type \" << optionmap[\"-a\"];\n    usage(std::cerr);\n    return 1;\n  }\n\n  int status = 0;\n\n  std::cout << \"Initialising graph...\" << std::endl;\n  maze->InitialiseGraph();\n  std::cout << \"Generating maze...\" << std::endl;\n  maze->GenerateMaze(algorithm);\n  if (optionmap[\"-t\"] == 0) {\n    std::cout << \"Rendering maze to '\" << outputprefix << \".svg'...\"\n              << std::endl;\n    maze->PrintMazeSVG(outputprefix);\n  } else {\n    std::cout << \"Exporting maze plotting parameters to '\" << outputprefix\n              << \".plt' ...\" << std::endl;\n    maze->PrintMazeGnuplot(outputprefix);\n    std::cout << \"Rendering maze to '\" << outputprefix\n              << \".png' using gnuplot...\" << std::endl;\n    status = system((\"gnuplot '\" + outputprefix + \".plt'\").c_str());\n  }\n  return status;\n}\n"
  },
  {
    "path": "src/apps/megaverse_test_app.cpp",
    "content": "#include <cstdlib>\n\n#include <opencv2/core/mat.hpp>\n#include <opencv2/imgproc.hpp>\n#include <opencv2/highgui.hpp>\n\n#include <util/util.hpp>\n#include <util/argparse.hpp>\n#include <util/os_utils.hpp>\n#include <util/tiny_logger.hpp>\n#include <util/tiny_profiler.hpp>\n\n#include <env/env.hpp>\n#include <env/vector_env.hpp>\n\n#include <scenarios/init.hpp>\n\n#if !defined(CORRADE_TARGET_APPLE)\n#include <v4r_rendering/v4r_env_renderer.hpp>\n#endif\n\n#include <magnum_rendering/magnum_env_renderer.hpp>\n\n#include \"viewer_args.hpp\"\n\nusing namespace Megaverse;\n\n\n// don't ask me, this is what waitKeyEx returns\nconstexpr auto keyUp = 65362, keyLeft = 65361, keyRight = 65363, keyDown = 65364;\n\n\nstd::string windowName(int envIdx, int agentIdx)\n{\n    auto wname = std::to_string(envIdx) + std::to_string(agentIdx);\n    return wname;\n}\n\n\nint mainLoop(VectorEnv &venv, EnvRenderer &renderer, bool viz, bool performanceTest, bool randomActions,\n             int W, int H, bool useVulkan, int delayMs, int maxNumFrames)\n{\n    if (performanceTest)\n        randomActions = true;\n\n    auto activeAgent = 0;\n    int numFrames = 0, prevNumFrames = 0;\n\n    const auto numEnvs = int(venv.envs.size()), numAgents = venv.envs.front()->getNumAgents();\n\n    if (viz) {\n        for (int envIdx = 0; envIdx < numEnvs; ++envIdx) {\n            for (int i = 0; i < numAgents; ++i) {\n                const auto wname = windowName(envIdx, i);\n                cv::namedWindow(wname);\n                cv::moveWindow(wname, int(W * i * 1.1), int(H * envIdx * 1.1));\n            }\n        }\n    }\n\n    venv.reset();\n\n#if defined(ARTIFICIAL_MEMLEAK)\n    std::vector<std::vector<int>> vvi;\n#endif\n\n    auto rng = venv.envs.front()->getRng();\n    tprof().startTimer(\"fps_period\");\n\n    bool shouldExit = false;\n    do {\n        tprof().startTimer(\"step\");\n        venv.step();\n        tprof().pauseTimer(\"step\");\n\n        for (int envIdx = 0; envIdx < int(venv.envs.size()); ++envIdx) {\n            for (int i = 0; i < venv.envs[envIdx]->getNumAgents(); ++i) {\n                const uint8_t *obsData = renderer.getObservation(envIdx, i);\n\n                if (viz) {\n                    cv::Mat mat(H, W, CV_8UC4, (char *) obsData);\n                    cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR);\n\n                    if (!useVulkan)\n                        cv::flip(mat, mat, 0);\n\n                    cv::imshow(windowName(envIdx, i), mat);\n                }\n            }\n        }\n\n        if (viz) {\n            auto latestAction = Action::Idle;\n            auto key = cv::waitKeyEx(delayMs);\n\n            switch (key) {\n                case 'w':\n                    latestAction |= Action::Forward;\n                    break;\n                case 's':\n                    latestAction |= Action::Backward;\n                    break;\n                case 'a':\n                    latestAction |= Action::Left;\n                    break;\n                case 'd':\n                    latestAction |= Action::Right;\n                    break;\n                case ' ':\n                    latestAction |= Action::Jump;\n                    break;\n\n                case keyLeft:\n                    latestAction |= Action::LookLeft;\n                    break;\n                case keyRight:\n                    latestAction |= Action::LookRight;\n                    break;\n                case keyUp:\n                    latestAction |= Action::LookUp;\n                    break;\n                case keyDown:\n                    latestAction |= Action::LookDown;\n                    break;\n\n                case '1':\n                case '2':\n                case '3':\n                case '4':\n                    activeAgent = key - 1;\n                    break;\n\n                default:\n                    break;\n            }\n\n            venv.envs.front()->setAction(activeAgent, latestAction);\n        }\n\n        if (randomActions) {\n            for (auto & env : venv.envs) {\n                for (int i = 0; i < env->getNumAgents(); ++i) {\n                    auto randomAction = randRange(0, int(Action::NumActions), rng);\n                    env->setAction(i, Action(1 << randomAction));\n                }\n            }\n        }\n\n        numFrames += numAgents * numEnvs;\n\n        if (numFrames > maxNumFrames) {\n            shouldExit = true;\n            TLOG(INFO) << \"Done: \" << numFrames;\n            break;\n        } else if (numFrames % 5000 == 0) {\n            auto elapsedTimeSec = tprof().stopTimer(\"fps_period\") / 1e6;\n            tprof().startTimer(\"fps_period\");\n\n            auto approxFps = float(numFrames - prevNumFrames) / elapsedTimeSec;\n            prevNumFrames = numFrames;\n\n            double vmUsage, residentSet;\n            unixProcessMemUsage(vmUsage, residentSet);\n\n#if defined(ARTIFICIAL_MEMLEAK)\n            // test artificial memleak\n            vvi.emplace_back(1024 * 1024, 3);\n            TLOG(INFO) << std::accumulate(vvi.back().begin(), vvi.back().end(), 0);\n#endif\n            TLOG(INFO) << \"Progress \" << numFrames << \"/\" << maxNumFrames << \". Approx FPS: \" << approxFps << \". VM usage: \" << (long long)vmUsage << \". RSS: \" << (long long)residentSet;\n        }\n    } while (!shouldExit);\n\n    return numFrames;\n}\n\n\nint main(int argc, char** argv)\n{\n    scenariosGlobalInit();\n\n    auto parser = viewerStandardArgParse(\"megaverse_test_app\");\n    parser.add_description(\"This app is designed to test the parallel execution engine and batched renderer\\n\"\n                           \"by simulating multiple environments at once. This app uses pretty much the same interface\\n\"\n                           \"as the Python Gym environment, sans the Python bindings. Whenever there is a problem\\n\"\n                           \"with the environment, it is much easier to debug this app directly, rather\\n\"\n                           \"than debugging the same code through Python.\\n\\n\"\n                           \"Example, render 12 agents at the same time:\\n\"\n                           \"megaverse_test_app --scenario Collect --visualize --num_envs 4 --num_simulation_threads 1 --num_agents 3 --hires\\n\\n\"\n                           \"Some performance figures for future reference (on 10-core Intel i9):\\n\"\n                           \"megaverse_test_app --scenario Empty --performance_test --num_envs 64 --num_simulation_threads 1 --num_agents 1\\n\"\n                           \"yields approximately 75000 FPS\\n\"\n                           \"megaverse_test_app --scenario Collect --performance_test --num_envs 64 --num_simulation_threads 1 --num_agents 1\\n\"\n                           \"yields approximately 27000 FPS\\n\");\n\n    parser.add_argument(\"--num_envs\")\n        .help(\"number of parallel environments to simulate\")\n        .default_value(64)\n        .scan<'i', int>();\n    parser.add_argument(\"--num_simulation_threads\")\n        .help(\"number of parallel CPU threads to use for Bullet\")\n        .default_value(1)\n        .scan<'i', int>();\n    parser.add_argument(\"--visualize\")\n        .help(\"Whether to render multiple environments on screen\")\n        .default_value(false)\n        .implicit_value(true);\n    parser.add_argument(\"--visualize\")\n        .help(\"Whether to render multiple environments on screen\")\n        .default_value(false)\n        .implicit_value(true);\n    parser.add_argument(\"--delay_ms\")\n        .help(\"Delay between rendered frames in milliseconds. Use only with --visualize\")\n        .default_value(1)\n        .scan<'i', int>();\n    parser.add_argument(\"--performance_test\")\n        .help(\"Run for a limited number of env frames (currently 200000) to test performance. Uses random actions.\")\n        .default_value(false)\n        .implicit_value(true);\n    parser.add_argument(\"--hires\")\n        .help(\"Render at high resolution. Only use this parameter with --visualize and if the total number of agents is small\")\n        .default_value(false)\n        .implicit_value(true);\n    parser.add_argument(\"--user_actions\")\n        .help(\"Allows the user to control agents (otherwise will use randomly generated actions). Use only with --visualize\")\n        .default_value(false)\n        .implicit_value(true);\n\n    parseArgs(parser, argc, argv);\n\n    const auto scenarioName = parser.get<std::string>(\"--scenario\");\n    const auto numAgents = parser.get<int>(\"--num_agents\");\n    const bool useVulkanRenderer = !parser.get<bool>(\"--use_opengl\");\n    const int numEnvs = parser.get<int>(\"--num_envs\");  // to test vectorized env interface\n    const int numSimulationThreads = parser.get<int>(\"--num_simulation_threads\");\n    const auto viz = parser.get<bool>(\"--visualize\");\n    const auto delayMs = parser.get<int>(\"--delay_ms\");\n    const auto performanceTest = parser.get<bool>(\"--performance_test\");\n    const auto hires = parser.get<bool>(\"--hires\");\n    const bool randomActions = !parser.get<bool>(\"--user_actions\");\n\n    const int W = hires ? 800 : 128, H = hires ? 450 : 72;\n    TLOG(INFO) << \"Rendering resolution is [\" << W << \"x\" << H << \"] per agent\";\n\n    const int maxNumFrames = performanceTest ? 400'000 : 2'000'000'000;\n\n    // FloatParams params{{Str::episodeLengthSec, 0.1f}};\n    FloatParams params{{}};\n\n    std::vector<std::unique_ptr<Env>> envs;\n    for (int i = 0; i < numEnvs; ++i) {\n        envs.emplace_back(std::make_unique<Env>(scenarioName, numAgents, params));\n        envs[i]->seed(42 + i);\n    }\n\n    std::unique_ptr<EnvRenderer> renderer;\n    if (useVulkanRenderer)\n#if defined (CORRADE_TARGET_APPLE)\n        TLOG(ERROR) << \"Vulkan not supported on MacOS\";\n#else\n        renderer = std::make_unique<V4REnvRenderer>(envs, W, H, nullptr, false);\n#endif\n    else {\n        constexpr auto debugDraw = false;\n        renderer = std::make_unique<MagnumEnvRenderer>(envs, W, H, debugDraw);\n    }\n\n    VectorEnv vectorEnv{envs, *renderer, numSimulationThreads};\n    vectorEnv.reset();\n\n    tprof().startTimer(\"loop\");\n    auto nFrames = mainLoop(vectorEnv, *renderer, viz, performanceTest, randomActions, W, H, useVulkanRenderer, delayMs, maxNumFrames);\n    const auto usecPassed = tprof().stopTimer(\"loop\");\n    tprof().stopTimer(\"step\");\n\n    vectorEnv.close();\n\n    const auto fps = nFrames / (usecPassed / 1e6);\n\n    TLOG(DEBUG) << \"\\n\\n\" << fps << \" FPS! \" << nFrames << \" frames\";\n\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "src/apps/viewer_app.cpp",
    "content": "#include <Magnum/Timeline.h>\n\n#include <util/tiny_logger.hpp>\n\n#include <env/env.hpp>\n#include <scenarios/init.hpp>\n\n#include <viewer/viewer.hpp>\n\n#include \"viewer_args.hpp\"\n\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\nusing namespace Megaverse;\n\n\nclass ViewerApp: public Viewer\n{\npublic:\n    explicit ViewerApp(Envs &envs, unsigned int minimalLoopPeriod, bool useVulkanRenderer, const Arguments& arguments);\n\nprivate:\n    void drawEvent() override;\n\n    void tickEvent() override;\n\n    void keyPressEvent(KeyEvent &event) override;\n    void keyReleaseEvent(KeyEvent &event) override;\n\n    void handleActions(const KeyEvent::Key &key, bool addAction);\n\nprivate:\n    Action currAction = Action::Idle;\n\n    Timeline timeline;\n};\n\nViewerApp::ViewerApp(Envs &envs, unsigned int minimalLoopPeriod, bool useVulkanRenderer, const Arguments& arguments)\n: Viewer{envs, useVulkanRenderer, nullptr, arguments}\n{\n    setMinimalLoopPeriod(minimalLoopPeriod);\n\n    timeline.start();\n}\n\nvoid ViewerApp::tickEvent()\n{\n    auto &env = envs[activeEnv];\n    env->setFrameDuration(timeline.previousFrameDuration());\n    env->setAction(activeAgent, currAction);\n\n    currAction &= ~Action::Interact;\n\n    env->step();\n    const auto done = env->isDone();\n\n    if (done) {\n        TLOG(INFO) << \"Done!\";\n\n        std::ostringstream s;\n        for (int i = 0; i < env->getNumAgents(); ++i) s << \" \" << env->getTotalReward(i);\n        TLOG(INFO) << \"Total reward: \" << s.str();\n        s.clear();\n\n        for (int i = 0; i < env->getNumAgents(); ++i) s << \" \" << env->trueObjective(i);\n        TLOG(INFO) << \"True objectives: \" << s.str();\n\n        env->reset();\n    }\n\n    Viewer::step(std::vector<bool>(1, done));\n}\n\nvoid ViewerApp::drawEvent()\n{\n    Viewer::drawEvent();\n    timeline.nextFrame();\n}\n\nvoid ViewerApp::keyPressEvent(KeyEvent &event)\n{\n    Viewer::keyPressEvent(event);\n\n    handleActions(event.key(), true);\n    event.setAccepted();\n}\n\nvoid ViewerApp::keyReleaseEvent(KeyEvent &event)\n{\n    Viewer::keyReleaseEvent(event);\n\n    handleActions(event.key(), false);\n    event.setAccepted();\n}\n\nvoid ViewerApp::handleActions(const KeyEvent::Key &key, bool addAction)\n{\n    auto a = Action::Idle;\n\n    switch(key) {\n        case KeyEvent::Key::W: a = Action::Forward; break;\n        case KeyEvent::Key::S: a = Action::Backward; break;\n        case KeyEvent::Key::A: a = Action::Left; break;\n        case KeyEvent::Key::D: a = Action::Right; break;\n\n        case KeyEvent::Key::Left: a = Action::LookLeft; break;\n        case KeyEvent::Key::Right: a = Action::LookRight; break;\n        case KeyEvent::Key::Up: a = Action::LookUp; break;\n        case KeyEvent::Key::Down: a = Action::LookDown; break;\n\n        case KeyEvent::Key::Space: a = Action::Jump; break;\n\n        case KeyEvent::Key::E: a = Action::Interact; break;\n\n        default: break;\n    }\n\n    if (a == Action::Idle)\n        return;\n\n    if (addAction)\n        currAction |= a;\n    else\n        currAction &= ~a;\n}\n\n\nint main(int argc, char** argv)\n{\n    scenariosGlobalInit();\n\n    auto parser = viewerStandardArgParse(\"viewer_app\");\n    parser.add_description(\"viewer_app can run any scenario in an interactive mode\");\n    parser.add_argument(\"--desired_fps\")\n        .help(\"rendering framerate for human perception; RL agents percieve the world at 15 FPS to avoid frameskip, hence the default value.\")\n        .default_value(15)\n        .scan<'i', int>();\n\n    parseArgs(parser, argc, argv);\n\n    const auto scenarioName = parser.get<std::string>(\"--scenario\");\n    const auto numAgents = parser.get<int>(\"--num_agents\");\n    const auto desiredFps = parser.get<int>(\"--desired_fps\");\n    const bool useVulkanRenderer = !parser.get<bool>(\"--use_opengl\");\n\n    FloatParams params{{Str::useUIRewardIndicators, 1.0f}};\n    auto env = std::make_unique<Env>(scenarioName, numAgents, params);\n#ifdef FIXED_SEED\n    env->seed(42);\n#endif\n    env->reset();\n\n    const unsigned int delayMs = 1000 / desiredFps;\n    env->setSimulationResolution(1.0f / float(desiredFps));\n\n    Envs envs;\n    envs.emplace_back(std::move(env));\n\n    ViewerApp app(envs, delayMs, useVulkanRenderer, {argc, argv});\n    return app.exec();\n}"
  },
  {
    "path": "src/apps/viewer_args.cpp",
    "content": "#include <util/argparse.hpp>\n\n#include <env/scenario.hpp>\n\n#include \"viewer_args.hpp\"\n\n\nargparse::ArgumentParser Megaverse::viewerStandardArgParse(const std::string &appName) {\n    argparse::ArgumentParser parser(appName);\n\n    parser.add_argument(\"-l\", \"--list_scenarios\")\n        .help(\"list registered scenario names\")\n        .action([&](const auto &) {\n            auto s = Scenario::registeredScenarios();\n            TLOG(INFO) << \"Scenarios: \" << s;\n        })\n        .default_value(false)\n        .implicit_value(true);\n    parser.add_argument(\"--scenario\")\n        .help(\"name of the scenario to run\")\n        .default_value(std::string{\"ObstaclesEasy\"});\n    parser.add_argument(\"--num_agents\")\n        .help(\"size of the team\")\n        .default_value(2)\n        .scan<'i', int>();\n\n    constexpr bool isApple =\n#if defined(CORRADE_TARGET_APPLE)\n        true;\n#else\n        false;\n#endif\n\n    parser.add_argument(\"--use_opengl\")\n        .help(\"Whether to use OpenGL renderer instead of fast Vulkan renderer (currently Vulkan is only supported in Linux)\")\n        .default_value(isApple)\n        .implicit_value(true);\n\n    return parser;\n}\n\nvoid Megaverse::parseArgs(argparse::ArgumentParser &p, int argc, char** argv)\n{\n    try {\n        p.parse_args(argc, argv);\n    } catch (const std::runtime_error &err) {\n        std::cerr << err.what() << std::endl;\n        std::cerr << p;\n        std::exit(EXIT_FAILURE);\n    }\n}\n"
  },
  {
    "path": "src/apps/viewer_args.hpp",
    "content": "#include <util/argparse.hpp>\n\nnamespace Megaverse\n{\n\nargparse::ArgumentParser viewerStandardArgParse(const std::string &appName);\nvoid parseArgs(argparse::ArgumentParser &p, int argc, char** argv);\n\n}"
  },
  {
    "path": "src/cmake/modules/FindCorrade.cmake",
    "content": "#.rst:\n# Find Corrade\n# ------------\n#\n# Finds the Corrade library. Basic usage::\n#\n#  find_package(Corrade REQUIRED)\n#\n# This module tries to find the base Corrade library and then defines the\n# following:\n#\n#  Corrade_FOUND                  - Whether the base library was found\n#  CORRADE_LIB_SUFFIX_MODULE      - Path to CorradeLibSuffix.cmake module\n#  CORRADE_INCLUDE_INSTALL_PREFIX - Prefix where to put platform-independent\n#   include and other files, defaults to ``.``. If a relative path is used,\n#   it's relative to :variable:`CMAKE_INSTALL_PREFIX`.\n#\n# This command will try to find only the base library, not the optional\n# components, which are:\n#\n#  Containers                   - Containers library\n#  PluginManager                - PluginManager library\n#  TestSuite                    - TestSuite library\n#  Utility                      - Utility library\n#  rc                           - corrade-rc executable\n#\n# Example usage with specifying additional components is::\n#\n#  find_package(Corrade REQUIRED Utility TestSuite)\n#\n# For each component is then defined:\n#\n#  Corrade_*_FOUND              - Whether the component was found\n#  Corrade::*                   - Component imported target\n#\n# The package is found if either debug or release version of each library is\n# found. If both debug and release libraries are found, proper version is\n# chosen based on actual build configuration of the project (i.e. Debug build\n# is linked to debug libraries, Release build to release libraries).\n#\n# Corrade conditionally defines ``CORRADE_IS_DEBUG_BUILD`` preprocessor\n# variable in case build configuration is ``Debug`` (not Corrade itself, but\n# build configuration of the project using it). Useful e.g. for selecting\n# proper plugin directory.\n#\n# Corrade defines the following custom target properties:\n#\n#  CORRADE_CXX_STANDARD         - C++ standard to require when compiling given\n#   target. Does nothing if :variable:`CMAKE_CXX_FLAGS` already contains\n#   particular standard setting flag or if given target contains\n#   :prop_tgt:`CMAKE_CXX_STANDARD` property. Allowed value is 11, 14 or 17.\n#  INTERFACE_CORRADE_CXX_STANDARD - C++ standard to require when using given\n#   target. Does nothing if :variable:`CMAKE_CXX_FLAGS` already contains\n#   particular standard setting flag or if given target contains\n#   :prop_tgt:`CMAKE_CXX_STANDARD` property. Allowed value is 11, 14 or 17.\n#  CORRADE_USE_PEDANTIC_FLAGS   - Enable additional compiler/linker flags.\n#   Boolean.\n#\n# These properties are inherited from directory properties, meaning that if you\n# set them on directories, they get implicitly set on all targets in given\n# directory (with a possibility to do target-specific overrides). All Corrade\n# libraries have the :prop_tgt:`INTERFACE_CORRADE_CXX_STANDARD` property set to\n# 11, meaning that you will always have at least C++11 enabled once you link to\n# any Corrade library.\n#\n# Features of found Corrade library are exposed in these variables:\n#\n#  CORRADE_MSVC2019_COMPATIBILITY - Defined if compiled with compatibility\n#   mode for MSVC 2019\n#  CORRADE_MSVC2017_COMPATIBILITY - Defined if compiled with compatibility\n#   mode for MSVC 2017\n#  CORRADE_MSVC2015_COMPATIBILITY - Defined if compiled with compatibility\n#   mode for MSVC 2015\n#  CORRADE_BUILD_DEPRECATED     - Defined if compiled with deprecated APIs\n#   included\n#  CORRADE_BUILD_STATIC         - Defined if compiled as static libraries.\n#   Default are shared libraries.\n#  CORRADE_BUILD_MULTITHREADED  - Defined if compiled in a way that makes it\n#   possible to safely use certain Corrade features simultaenously in multiple\n#   threads\n#  CORRADE_TARGET_UNIX          - Defined if compiled for some Unix flavor\n#   (Linux, BSD, macOS)\n#  CORRADE_TARGET_APPLE         - Defined if compiled for Apple platforms\n#  CORRADE_TARGET_IOS           - Defined if compiled for iOS (device or\n#   simulator)\n#  CORRADE_TARGET_IOS_SIMULATOR - Defined if compiled for iOS Simulator\n#  CORRADE_TARGET_WINDOWS       - Defined if compiled for Windows\n#  CORRADE_TARGET_WINDOWS_RT    - Defined if compiled for Windows RT\n#  CORRADE_TARGET_EMSCRIPTEN    - Defined if compiled for Emscripten\n#  CORRADE_TARGET_ANDROID       - Defined if compiled for Android\n#  CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT - Defined if PluginManager\n#   doesn't support dynamic plugin loading due to platform limitations\n#  CORRADE_TESTSUITE_TARGET_XCTEST - Defined if TestSuite is targetting Xcode\n#   XCTest\n#  CORRADE_UTILITY_USE_ANSI_COLORS - Defined if ANSI escape sequences are used\n#   for colored output with Utility::Debug on Windows\n#\n# Additionally these variables are defined for internal usage:\n#\n#  CORRADE_INCLUDE_DIR          - Root include dir\n#  CORRADE_*_LIBRARY_DEBUG      - Debug version of given library, if found\n#  CORRADE_*_LIBRARY_RELEASE    - Release version of given library, if found\n#  CORRADE_*_EXECUTABLE         - Location of given executable, if found\n#  CORRADE_USE_MODULE           - Path to UseCorrade.cmake module (included\n#   automatically)\n#  CORRADE_TESTSUITE_XCTEST_RUNNER - Path to XCTestRunner.mm.in file\n#  CORRADE_TESTSUITE_ADB_RUNNER - Path to AdbRunner.sh file\n#  CORRADE_PEDANTIC_COMPILER_OPTIONS - List of pedantic compiler options used\n#   for targets with :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS` enabled\n#  CORRADE_PEDANTIC_COMPILER_DEFINITIONS - List of pedantic compiler\n#   definitions used for targets with :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS`\n#   enabled\n#\n# Workflows without :prop_tgt:`IMPORTED` targets are deprecated and the\n# following variables are included just for backwards compatibility and only if\n# :variable:`CORRADE_BUILD_DEPRECATED` is enabled:\n#\n#  CORRADE_CXX_FLAGS            - Pedantic compile flags. Use\n#   :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS` property or\n#   :variable:`CORRADE_PEDANTIC_COMPILER_DEFINITIONS` /\n#   :variable:`CORRADE_PEDANTIC_COMPILER_OPTIONS` list variables instead.\n#\n# Corrade provides these macros and functions:\n#\n# .. command:: corrade_add_test\n#\n# Add unit test using Corrade's TestSuite::\n#\n#  corrade_add_test(<test name>\n#                   <sources>...\n#                   [LIBRARIES <libraries>...]\n#                   [FILES <files>...]\n#                   [ARGUMENTS <arguments>...])\n#\n# Test name is also executable name. You can use ``LIBRARIES`` to specify\n# libraries to link with instead of using :command:`target_link_libraries()`.\n# The ``Corrade::TestSuite`` target is linked automatically to each test. Note\n# that the :command:`enable_testing()` function must be called explicitly.\n# Arguments passed after ``ARGUMENTS`` will be appended to the test\n# command line. ``ARGUMENTS`` are supported everywhere except when\n# ``CORRADE_TESTSUITE_TARGET_XCTEST`` is enabled.\n#\n# You can list files needed by the test in the ``FILES`` section. If given\n# filename is relative, it is treated relatively to `CMAKE_CURRENT_SOURCE_DIR`.\n# The files are added to the :prop_test:`REQUIRED_FILES` target property. On\n# Emscripten they are bundled to the executable and available in the virtual\n# filesystem root. On Android they are copied along the executable to the\n# target. In case of Emscripten and Android, if the file is absolute or\n# contains ``..``, only the leaf name is used. Alternatively you can have a\n# filename formatted as ``<input>@<output>``, in which case the ``<input>`` is\n# treated as local filesystem location and ``<output>`` as remote/virtual\n# filesystem location. The remote location can't be absolute or contain ``..``\n# / ``@`` characters.\n#\n# Unless :variable:`CORRADE_TESTSUITE_TARGET_XCTEST` is set, test cases on iOS\n# targets are created as bundles with bundle identifier set to CMake project\n# name by default. Use the cache variable :variable:`CORRADE_TESTSUITE_BUNDLE_IDENTIFIER_PREFIX`\n# to change it to something else.\n#\n# .. command:: corrade_add_resource\n#\n# Compile data resources into application binary::\n#\n#  corrade_add_resource(<name> <resources.conf>)\n#\n# Depends on ``Corrade::rc``, which is part of Corrade utilities. This command\n# generates resource data using given configuration file in current build\n# directory. Argument name is name under which the resources can be explicitly\n# loaded. Variable ``<name>`` contains compiled resource filename, which is\n# then used for compiling library / executable. On CMake >= 3.1 the\n# `resources.conf` file can contain UTF-8-encoded filenames. Example usage::\n#\n#  corrade_add_resource(app_resources resources.conf)\n#  add_executable(app source1 source2 ... ${app_resources})\n#\n# .. command:: corrade_add_plugin\n#\n# Add dynamic plugin::\n#\n#  corrade_add_plugin(<plugin name>\n#                     \"<debug binary install dir>;<debug library install dir>\"\n#                     \"<release binary install dir>;<release library install dir>\"\n#                     <metadata file>\n#                     <sources>...)\n#\n# The macro adds preprocessor directive ``CORRADE_DYNAMIC_PLUGIN``. Additional\n# libraries can be linked in via :command:`target_link_libraries(plugin_name ...) <target_link_libraries>`.\n# On DLL platforms, the plugin DLLs and metadata files are put into\n# ``<debug binary install dir>``/``<release binary install dir>`` and the\n# ``*.lib`` files into ``<debug library install dir>``/``<release library install dir>``.\n# On non-DLL platforms everything is put into ``<debug library install dir>``/\n# ``<release library install dir>``.\n#\n#  corrade_add_plugin(<plugin name>\n#                     <debug install dir>\n#                     <release install dir>\n#                     <metadata file>\n#                     <sources>...)\n#\n# Unline the above version this puts everything into ``<debug install dir>`` on\n# both DLL and non-DLL platforms. If ``<debug install dir>`` is set to\n# :variable:`CMAKE_CURRENT_BINARY_DIR` (e.g. for testing purposes), the files\n# are copied directly, without the need to perform install step. Note that the\n# files are actually put into configuration-based subdirectory, i.e.\n# ``${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}``. See documentation of\n# :variable:`CMAKE_CFG_INTDIR` variable for more information.\n#\n# .. command:: corrade_add_static_plugin\n#\n# Add static plugin::\n#\n#  corrade_add_static_plugin(<plugin name>\n#                            \"<binary install dir>;<library install dir>\"\n#                            <metadata file>\n#                            <sources>...)\n#\n# The macro adds preprocessor directive ``CORRADE_STATIC_PLUGIN``. Additional\n# libraries can be linked in via :command:`target_link_libraries(plugin_name ...) <target_link_libraries>`.\n# The ``<binary install dir>`` is ignored and included just for compatibility\n# with the :command:`corrade_add_plugin` command, everything is installed into\n# ``<library install dir>``. Note that plugins built in debug configuration\n# (e.g. with :variable:`CMAKE_BUILD_TYPE` set to ``Debug``) have ``\"-d\"``\n# suffix to make it possible to have both debug and release plugins installed\n# alongside each other.\n#\n#  corrade_add_static_plugin(<plugin name>\n#                            <install dir>\n#                            <metadata file>\n#                            <sources>...)\n#\n# Equivalent to the above with ``<library install dir>`` set to ``<install dir>``.\n# If ``<install dir>`` is set to :variable:`CMAKE_CURRENT_BINARY_DIR` (e.g. for\n# testing purposes), no installation rules are added.\n#\n# .. command:: corrade_find_dlls_for_libs\n#\n# Find corresponding DLLs for library files::\n#\n#  corrade_find_dlls_for_libs(<output variable> <libs>...)\n#\n# Available only on Windows, for all ``*.lib`` files tries to find\n# corresponding DLL file. Useful for bundling dependencies for e.g. WinRT\n# packages.\n#\n\n#\n#   This file is part of Corrade.\n#\n#   Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,\n#               2017, 2018, 2019 Vladimír Vondruš <mosra@centrum.cz>\n#\n#   Permission is hereby granted, free of charge, to any person obtaining a\n#   copy of this software and associated documentation files (the \"Software\"),\n#   to deal in the Software without restriction, including without limitation\n#   the rights to use, copy, modify, merge, publish, distribute, sublicense,\n#   and/or sell copies of the Software, and to permit persons to whom the\n#   Software is furnished to do so, subject to the following conditions:\n#\n#   The above copyright notice and this permission notice shall be included\n#   in all copies or substantial portions of the Software.\n#\n#   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#   DEALINGS IN THE SOFTWARE.\n#\n\n# Root include dir\nfind_path(CORRADE_INCLUDE_DIR\n    NAMES Corrade/Corrade.h)\nmark_as_advanced(CORRADE_INCLUDE_DIR)\n\n# Configuration file\nfind_file(_CORRADE_CONFIGURE_FILE configure.h\n    HINTS ${CORRADE_INCLUDE_DIR}/Corrade/)\nmark_as_advanced(_CORRADE_CONFIGURE_FILE)\n\n# We need to open configure.h file from CORRADE_INCLUDE_DIR before we check for\n# the components. Bail out with proper error message if it wasn't found. The\n# complete check with all components is further below.\nif(NOT CORRADE_INCLUDE_DIR)\n    include(FindPackageHandleStandardArgs)\n    find_package_handle_standard_args(Corrade\n        REQUIRED_VARS CORRADE_INCLUDE_DIR _CORRADE_CONFIGURE_FILE)\nendif()\n\n# Read flags from configuration\nfile(READ ${_CORRADE_CONFIGURE_FILE} _corradeConfigure)\nset(_corradeFlags\n    # WARNING: CAREFUL HERE, the string(FIND) succeeds even if a subset is\n    # found -- so e.g. looking for TARGET_GL will match TARGET_GLES2 as well.\n    # So far that's not a problem, but might become an issue for new flags.\n    MSVC2015_COMPATIBILITY\n    MSVC2017_COMPATIBILITY\n    MSVC2019_COMPATIBILITY\n    BUILD_DEPRECATED\n    BUILD_STATIC\n    BUILD_MULTITHREADED\n    TARGET_UNIX\n    TARGET_APPLE\n    TARGET_IOS\n    TARGET_IOS_SIMULATOR\n    TARGET_WINDOWS\n    TARGET_WINDOWS_RT\n    TARGET_EMSCRIPTEN\n    TARGET_ANDROID\n    PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT\n    TESTSUITE_TARGET_XCTEST\n    UTILITY_USE_ANSI_COLORS)\nforeach(_corradeFlag ${_corradeFlags})\n    string(FIND \"${_corradeConfigure}\" \"#define CORRADE_${_corradeFlag}\" _corrade_${_corradeFlag})\n    if(NOT _corrade_${_corradeFlag} EQUAL -1)\n        set(CORRADE_${_corradeFlag} 1)\n    endif()\nendforeach()\n\n# CMake module dir\nfind_path(_CORRADE_MODULE_DIR\n    NAMES UseCorrade.cmake CorradeLibSuffix.cmake\n    PATH_SUFFIXES share/cmake/Corrade)\nmark_as_advanced(_CORRADE_MODULE_DIR)\n\nset(CORRADE_USE_MODULE ${_CORRADE_MODULE_DIR}/UseCorrade.cmake)\nset(CORRADE_LIB_SUFFIX_MODULE ${_CORRADE_MODULE_DIR}/CorradeLibSuffix.cmake)\n\n# Ensure that all inter-component dependencies are specified as well\nforeach(_component ${Corrade_FIND_COMPONENTS})\n    string(TOUPPER ${_component} _COMPONENT)\n\n    if(_component STREQUAL Containers)\n        set(_CORRADE_${_COMPONENT}_DEPENDENCIES Utility)\n    elseif(_component STREQUAL Interconnect)\n        set(_CORRADE_${_COMPONENT}_DEPENDENCIES Utility)\n    elseif(_component STREQUAL PluginManager)\n        set(_CORRADE_${_COMPONENT}_DEPENDENCIES Containers Utility rc)\n    elseif(_component STREQUAL TestSuite)\n        set(_CORRADE_${_COMPONENT}_DEPENDENCIES Utility Main) # see below\n    elseif(_component STREQUAL Utility)\n        set(_CORRADE_${_COMPONENT}_DEPENDENCIES Containers rc)\n    endif()\n\n    # Mark the dependencies as required if the component is also required\n    if(Corrade_FIND_REQUIRED_${_component})\n        foreach(_dependency ${_CORRADE_${_COMPONENT}_DEPENDENCIES})\n            set(Corrade_FIND_REQUIRED_${_dependency} TRUE)\n        endforeach()\n    endif()\n\n    list(APPEND _CORRADE_ADDITIONAL_COMPONENTS ${_CORRADE_${_COMPONENT}_DEPENDENCIES})\n\n    # Main is linked only in corrade_add_test(), not to everything that depends\n    # on TestSuite, so remove it from the list again once we filled the above\n    # variables\n    if(_component STREQUAL TestSuite)\n        set(_CORRADE_${_COMPONENT}_DEPENDENCIES Utility)\n    endif()\nendforeach()\n\n# Join the lists, remove duplicate components\nif(_CORRADE_ADDITIONAL_COMPONENTS)\n    list(INSERT Corrade_FIND_COMPONENTS 0 ${_CORRADE_ADDITIONAL_COMPONENTS})\nendif()\nif(Corrade_FIND_COMPONENTS)\n    list(REMOVE_DUPLICATES Corrade_FIND_COMPONENTS)\nendif()\n\n# Component distinction\nset(_CORRADE_LIBRARY_COMPONENTS \"^(Containers|Interconnect|Main|PluginManager|TestSuite|Utility)$\")\nif(CORRADE_TARGET_WINDOWS)\n    # CorradeMain is a real library only on windows, a dummy target elsewhere\n    set(_CORRADE_HEADER_ONLY_COMPONENTS \"^(Containers)$\")\nelse()\n    set(_CORRADE_HEADER_ONLY_COMPONENTS \"^(Containers|Main)$\")\nendif()\nset(_CORRADE_EXECUTABLE_COMPONENTS \"^(rc)$\")\n\n# Find all components\nforeach(_component ${Corrade_FIND_COMPONENTS})\n    string(TOUPPER ${_component} _COMPONENT)\n\n    # Create imported target in case the library is found. If the project is\n    # added as subproject to CMake, the target already exists and all the\n    # required setup is already done from the build tree.\n    if(TARGET Corrade::${_component})\n        set(Corrade_${_component}_FOUND TRUE)\n    else()\n        # Library (and not header-only) components\n        if(_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS} AND NOT _component MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS})\n            add_library(Corrade::${_component} UNKNOWN IMPORTED)\n\n            # Try to find both debug and release version\n            find_library(CORRADE_${_COMPONENT}_LIBRARY_DEBUG Corrade${_component}-d)\n            find_library(CORRADE_${_COMPONENT}_LIBRARY_RELEASE Corrade${_component})\n            mark_as_advanced(CORRADE_${_COMPONENT}_LIBRARY_DEBUG\n                CORRADE_${_COMPONENT}_LIBRARY_RELEASE)\n\n            if(CORRADE_${_COMPONENT}_LIBRARY_RELEASE)\n                set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                    IMPORTED_CONFIGURATIONS RELEASE)\n                set_property(TARGET Corrade::${_component} PROPERTY\n                    IMPORTED_LOCATION_RELEASE ${CORRADE_${_COMPONENT}_LIBRARY_RELEASE})\n            endif()\n\n            if(CORRADE_${_COMPONENT}_LIBRARY_DEBUG)\n                set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                    IMPORTED_CONFIGURATIONS DEBUG)\n                set_property(TARGET Corrade::${_component} PROPERTY\n                    IMPORTED_LOCATION_DEBUG ${CORRADE_${_COMPONENT}_LIBRARY_DEBUG})\n            endif()\n        endif()\n\n        # Header-only library components\n        if(_component MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS})\n            add_library(Corrade::${_component} INTERFACE IMPORTED)\n        endif()\n\n        # Default include path names to look for for library / header-only\n        # components\n        if(_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS})\n            set(_CORRADE_${_COMPONENT}_INCLUDE_PATH_SUFFIX Corrade/${_component})\n            set(_CORRADE_${_COMPONENT}_INCLUDE_PATH_NAMES ${_component}.h)\n        endif()\n\n        # Executable components\n        if(_component MATCHES ${_CORRADE_EXECUTABLE_COMPONENTS})\n            add_executable(Corrade::${_component} IMPORTED)\n\n            find_program(CORRADE_${_COMPONENT}_EXECUTABLE corrade-${_component})\n            mark_as_advanced(CORRADE_${_COMPONENT}_EXECUTABLE)\n\n            if(CORRADE_${_COMPONENT}_EXECUTABLE)\n                set_property(TARGET Corrade::${_component} PROPERTY\n                    IMPORTED_LOCATION ${CORRADE_${_COMPONENT}_EXECUTABLE})\n            endif()\n        endif()\n\n        # No special setup for Containers library\n\n        # Interconnect library\n        if(_component STREQUAL Interconnect)\n            # Disable /OPT:ICF on MSVC, which merges functions with identical\n            # contents and thus breaks signal comparison\n            if(CORRADE_TARGET_WINDOWS AND CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n                if(CMAKE_VERSION VERSION_LESS 3.13)\n                    set_property(TARGET Corrade::${_component} PROPERTY\n                        INTERFACE_LINK_LIBRARIES \"-OPT:NOICF,REF\")\n                else()\n                    set_property(TARGET Corrade::${_component} PROPERTY\n                        INTERFACE_LINK_OPTIONS \"/OPT:NOICF,REF\")\n                endif()\n            endif()\n\n        # Main library\n        elseif(_component STREQUAL Main)\n            set(_CORRADE_${_COMPONENT}_INCLUDE_PATH_SUFFIX Corrade)\n            set(_CORRADE_${_COMPONENT}_INCLUDE_PATH_NAMES Corrade.h)\n\n            if(CORRADE_TARGET_WINDOWS)\n                if(NOT MINGW)\n                    # Abusing INTERFACE_LINK_LIBRARIES because\n                    # INTERFACE_LINK_OPTIONS is only since 3.13. They treat\n                    # things with `-` in front as linker flags and fortunately\n                    # I can use `-ENTRY` instead of `/ENTRY`.\n                    # https://gitlab.kitware.com/cmake/cmake/issues/16543\n                    set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES \"-ENTRY:$<$<NOT:$<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>>:wmainCRTStartup>$<$<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>:wWinMainCRTStartup>\")\n                else()\n                    set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES \"-municode\")\n                endif()\n            endif()\n\n        # PluginManager library\n        elseif(_component STREQUAL PluginManager)\n            # -ldl is handled by Utility now\n\n        # TestSuite library has some additional files\n        elseif(_component STREQUAL TestSuite)\n            # XCTest runner file\n            if(CORRADE_TESTSUITE_TARGET_XCTEST)\n                find_file(CORRADE_TESTSUITE_XCTEST_RUNNER XCTestRunner.mm.in\n                    PATH_SUFFIXES share/corrade/TestSuite)\n                set(CORRADE_TESTSUITE_XCTEST_RUNNER_NEEDED CORRADE_TESTSUITE_XCTEST_RUNNER)\n\n            # ADB runner file\n            elseif(CORRADE_TARGET_ANDROID)\n                find_file(CORRADE_TESTSUITE_ADB_RUNNER AdbRunner.sh\n                    PATH_SUFFIXES share/corrade/TestSuite)\n                set(CORRADE_TESTSUITE_ADB_RUNNER_NEEDED CORRADE_TESTSUITE_ADB_RUNNER)\n\n            # Emscripten runner file\n            elseif(CORRADE_TARGET_EMSCRIPTEN)\n                find_file(CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER EmscriptenRunner.html.in\n                    PATH_SUFFIXES share/corrade/TestSuite)\n                set(CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER_NEEDED CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER)\n            endif()\n\n        # Utility library (contains all setup that is used by others)\n        elseif(_component STREQUAL Utility)\n            # Top-level include directory\n            set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                INTERFACE_INCLUDE_DIRECTORIES ${CORRADE_INCLUDE_DIR})\n\n            # Require (at least) C++11 for users\n            set_property(TARGET Corrade::${_component} PROPERTY\n                INTERFACE_CORRADE_CXX_STANDARD 11)\n            set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                COMPATIBLE_INTERFACE_NUMBER_MAX CORRADE_CXX_STANDARD)\n\n            # Directory::libraryLocation() needs this\n            if(CORRADE_TARGET_UNIX)\n                set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})\n            endif()\n            # AndroidLogStreamBuffer class needs to be linked to log library\n            if(CORRADE_TARGET_ANDROID)\n                set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES \"log\")\n            endif()\n        endif()\n\n        # Find library includes\n        if(_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS})\n            find_path(_CORRADE_${_COMPONENT}_INCLUDE_DIR\n                NAMES ${_CORRADE_${_COMPONENT}_INCLUDE_PATH_NAMES}\n                HINTS ${CORRADE_INCLUDE_DIR}/${_CORRADE_${_COMPONENT}_INCLUDE_PATH_SUFFIX})\n            mark_as_advanced(_CORRADE_${_COMPONENT}_INCLUDE_DIR)\n        endif()\n\n        # Add inter-library dependencies\n        if(_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS} OR _component MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS})\n            foreach(_dependency ${_CORRADE_${_COMPONENT}_DEPENDENCIES})\n                if(_dependency MATCHES ${_CORRADE_LIBRARY_COMPONENTS} OR _dependency MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS})\n                    set_property(TARGET Corrade::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES Corrade::${_dependency})\n                endif()\n            endforeach()\n        endif()\n\n        # Decide if the component was found\n        if((_component MATCHES ${_CORRADE_LIBRARY_COMPONENTS} AND _CORRADE_${_COMPONENT}_INCLUDE_DIR AND (_component MATCHES ${_CORRADE_HEADER_ONLY_COMPONENTS} OR CORRADE_${_COMPONENT}_LIBRARY_RELEASE OR CORRADE_${_COMPONENT}_LIBRARY_DEBUG)) OR (_component MATCHES ${_CORRADE_EXECUTABLE_COMPONENTS} AND CORRADE_${_COMPONENT}_EXECUTABLE))\n            set(Corrade_${_component}_FOUND TRUE)\n        else()\n            set(Corrade_${_component}_FOUND FALSE)\n        endif()\n    endif()\nendforeach()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(Corrade REQUIRED_VARS\n    CORRADE_INCLUDE_DIR\n    _CORRADE_MODULE_DIR\n    _CORRADE_CONFIGURE_FILE\n    ${CORRADE_TESTSUITE_XCTEST_RUNNER_NEEDED}\n    ${CORRADE_TESTSUITE_ADB_RUNNER_NEEDED}\n    ${CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER_NEEDED}\n    HANDLE_COMPONENTS)\n\n# Finalize the finding process\ninclude(${CORRADE_USE_MODULE})\n\n# Installation dirs\nset(CORRADE_INCLUDE_INSTALL_PREFIX \".\"\n    CACHE STRING \"Prefix where to put platform-independent include and other files\")\n\nset(CORRADE_INCLUDE_INSTALL_DIR ${CORRADE_INCLUDE_INSTALL_PREFIX}/include/Corrade)\n"
  },
  {
    "path": "src/cmake/modules/FindEGL.cmake",
    "content": "#.rst:\n# Find EGL\n# --------\n#\n# Finds the EGL library. This module defines:\n#\n#  EGL_FOUND            - True if EGL library is found\n#  EGL::EGL             - EGL imported target\n#\n# Additionally these variables are defined for internal usage:\n#\n#  EGL_LIBRARY          - EGL library\n#  EGL_INCLUDE_DIR      - Include dir\n#\n\n#\n#   This file is part of Magnum.\n#\n#   Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,\n#               2020 Vladimír Vondruš <mosra@centrum.cz>\n#\n#   Permission is hereby granted, free of charge, to any person obtaining a\n#   copy of this software and associated documentation files (the \"Software\"),\n#   to deal in the Software without restriction, including without limitation\n#   the rights to use, copy, modify, merge, publish, distribute, sublicense,\n#   and/or sell copies of the Software, and to permit persons to whom the\n#   Software is furnished to do so, subject to the following conditions:\n#\n#   The above copyright notice and this permission notice shall be included\n#   in all copies or substantial portions of the Software.\n#\n#   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#   DEALINGS IN THE SOFTWARE.\n#\n\n# Under Emscripten, GL is linked implicitly. With MINIMAL_RUNTIME you need to\n# specify -lGL. Simply set the library name to that.\nif(CORRADE_TARGET_EMSCRIPTEN)\n    set(EGL_LIBRARY GL CACHE STRING \"Path to a library.\" FORCE)\nelse()\n    find_library(EGL_LIBRARY NAMES\n            EGL\n\n            # ANGLE (CMake doesn't search for lib prefix on Windows)\n            libEGL\n\n            # On iOS a part of OpenGLES\n            OpenGLES)\nendif()\n\n# Include dir\nfind_path(EGL_INCLUDE_DIR NAMES\n        EGL/egl.h\n\n        # iOS\n        EAGL.h)\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(EGL DEFAULT_MSG\n        EGL_LIBRARY\n        EGL_INCLUDE_DIR)\n\nif(NOT TARGET EGL::EGL)\n    # Work around BUGGY framework support on macOS. Do this also in case of\n    # Emscripten, since there we don't have a location either.\n    # http://public.kitware.com/pipermail/cmake/2016-April/063179.html\n    if((APPLE AND ${EGL_LIBRARY} MATCHES \"\\\\.framework$\") OR CORRADE_TARGET_EMSCRIPTEN)\n        add_library(EGL::EGL INTERFACE IMPORTED)\n        set_property(TARGET EGL::EGL APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES ${EGL_LIBRARY})\n    else()\n        add_library(EGL::EGL UNKNOWN IMPORTED)\n        set_property(TARGET EGL::EGL PROPERTY\n                IMPORTED_LOCATION ${EGL_LIBRARY})\n    endif()\n\n    set_target_properties(EGL::EGL PROPERTIES\n            INTERFACE_INCLUDE_DIRECTORIES ${EGL_INCLUDE_DIR})\nendif()\n\nmark_as_advanced(EGL_LIBRARY EGL_INCLUDE_DIR)\n"
  },
  {
    "path": "src/cmake/modules/FindMagnum.cmake",
    "content": "#.rst:\n# Find Magnum\n# -----------\n#\n# Finds the Magnum library. Basic usage::\n#\n#  find_package(Magnum REQUIRED)\n#\n# This module tries to find the base Magnum library and then defines the\n# following:\n#\n#  Magnum_FOUND                 - Whether the base library was found\n#  MAGNUM_DEPLOY_PREFIX         - Prefix where to put final application\n#   executables, defaults to ``.``. If a relative path is used, it's relative\n#   to :variable:`CMAKE_INSTALL_PREFIX`.\n#  MAGNUM_INCLUDE_INSTALL_PREFIX - Prefix where to put platform-independent\n#   include and other files, defaults to ``.``. If a relative path is used,\n#   it's relative to :variable:`CMAKE_INSTALL_PREFIX`.\n#  MAGNUM_PLUGINS_DEBUG_DIR     - Base directory with dynamic plugins for\n#   debug builds, defaults to magnum-d/ subdirectory of dir where Magnum\n#   library was found\n#  MAGNUM_PLUGINS_RELEASE_DIR   - Base directory with dynamic plugins for\n#   release builds, defaults to magnum/ subdirectory of dir where Magnum\n#   library was found\n#  MAGNUM_PLUGINS_DIR           - Base directory with dynamic plugins, defaults\n#   to :variable:`MAGNUM_PLUGINS_RELEASE_DIR` in release builds and\n#   multi-configuration builds or to :variable:`MAGNUM_PLUGINS_DEBUG_DIR` in\n#   debug builds\n#  MAGNUM_PLUGINS_FONT[|_DEBUG|_RELEASE]_DIR - Directory with dynamic font\n#   plugins\n#  MAGNUM_PLUGINS_FONTCONVERTER[|_DEBUG|_RELEASE]_DIR - Directory with dynamic\n#   font converter plugins\n#  MAGNUM_PLUGINS_IMAGECONVERTER[|_DEBUG|_RELEASE]_DIR - Directory with dynamic\n#   image converter plugins\n#  MAGNUM_PLUGINS_IMPORTER[|_DEBUG|_RELEASE]_DIR  - Directory with dynamic\n#   importer plugins\n#  MAGNUM_PLUGINS_AUDIOIMPORTER[|_DEBUG|_RELEASE]_DIR - Directory with dynamic\n#   audio importer plugins\n#\n# If Magnum is built for Emscripten, the following variables contain paths to\n# various support files:\n#\n#  MAGNUM_EMSCRIPTENAPPLICATION_JS - Path to the EmscriptenApplication.js file\n#  MAGNUM_WINDOWLESSEMSCRIPTENAPPLICATION_JS - Path to the\n#   WindowlessEmscriptenApplication.js file\n#  MAGNUM_WEBAPPLICATION_CSS    - Path to the WebApplication.css file\n#\n# This command will try to find only the base library, not the optional\n# components. The base library depends on Corrade and OpenGL libraries (or\n# OpenGL ES libraries). Additional dependencies are specified by the\n# components. The optional components are:\n#\n#  AnyAudioImporter             - Any audio importer\n#  AnyImageConverter            - Any image converter\n#  AnyImageImporter             - Any image importer\n#  AnySceneImporter             - Any scene importer\n#  Audio                        - Audio library\n#  DebugTools                   - DebugTools library\n#  GL                           - GL library\n#  MeshTools                    - MeshTools library\n#  Primitives                   - Primitives library\n#  SceneGraph                   - SceneGraph library\n#  Shaders                      - Shaders library\n#  Text                         - Text library\n#  TextureTools                 - TextureTools library\n#  Trade                        - Trade library\n#  Vk                           - Vk library\n#  AndroidApplication           - Android application\n#  EmscriptenApplication        - Emscripten application\n#  GlfwApplication              - GLFW application\n#  GlxApplication               - GLX application\n#  Sdl2Application              - SDL2 application\n#  XEglApplication              - X/EGL application\n#  WindowlessCglApplication     - Windowless CGL application\n#  WindowlessEglApplication     - Windowless EGL application\n#  WindowlessGlxApplication     - Windowless GLX application\n#  WindowlessIosApplication     - Windowless iOS application\n#  WindowlessWglApplication     - Windowless WGL application\n#  WindowlessWindowsEglApplication - Windowless Windows/EGL application\n#  CglContext                   - CGL context\n#  EglContext                   - EGL context\n#  GlxContext                   - GLX context\n#  WglContext                   - WGL context\n#  OpenGLTester                 - OpenGLTester class\n#  MagnumFont                   - Magnum bitmap font plugin\n#  MagnumFontConverter          - Magnum bitmap font converter plugin\n#  ObjImporter                  - OBJ importer plugin\n#  TgaImageConverter            - TGA image converter plugin\n#  TgaImporter                  - TGA importer plugin\n#  WavAudioImporter             - WAV audio importer plugin\n#  distancefieldconverter       - magnum-distancefieldconverter executable\n#  fontconverter                - magnum-fontconverter executable\n#  imageconverter               - magnum-imageconverter executable\n#  gl-info                      - magnum-gl-info executable\n#  al-info                      - magnum-al-info executable\n#\n# Example usage with specifying additional components is::\n#\n#  find_package(Magnum REQUIRED Trade MeshTools Primitives GlfwApplication)\n#\n# For each component is then defined:\n#\n#  Magnum_*_FOUND               - Whether the component was found\n#  Magnum::*                    - Component imported target\n#\n# If exactly one ``*Application`` or exactly one ``Windowless*Application``\n# component is requested and found, its target is available in convenience\n# alias ``Magnum::Application`` / ``Magnum::WindowlessApplication`` to simplify\n# porting. Similarly, if exactly one ``*Context`` component is requested and\n# found, its target is available in convenience alias ``Magnum::GLContext``.\n#\n# The package is found if either debug or release version of each requested\n# library (or plugin) is found. If both debug and release libraries (or\n# plugins) are found, proper version is chosen based on actual build\n# configuration of the project (i.e. Debug build is linked to debug libraries,\n# Release build to release libraries). Note that this autodetection might fail\n# for the :variable:`MAGNUM_PLUGINS_DIR` variable, especially on\n# multi-configuration build systems. You can make use of\n# ``CORRADE_IS_DEBUG_BUILD`` preprocessor variable along with\n# ``MAGNUM_PLUGINS_*_DEBUG_DIR`` / ``MAGNUM_PLUGINS_*_RELEASE_DIR`` variables\n# to decide in preprocessing step.\n#\n# Features of found Magnum library are exposed in these variables:\n#\n#  MAGNUM_BUILD_DEPRECATED      - Defined if compiled with deprecated APIs\n#   included\n#  MAGNUM_BUILD_STATIC          - Defined if compiled as static libraries\n#  MAGNUM_TARGET_GL             - Defined if compiled with OpenGL interop\n#  MAGNUM_TARGET_GLES           - Defined if compiled for OpenGL ES\n#  MAGNUM_TARGET_GLES2          - Defined if compiled for OpenGL ES 2.0\n#  MAGNUM_TARGET_GLES3          - Defined if compiled for OpenGL ES 3.0\n#  MAGNUM_TARGET_DESKTOP_GLES   - Defined if compiled with OpenGL ES\n#   emulation on desktop OpenGL\n#  MAGNUM_TARGET_WEBGL          - Defined if compiled for WebGL\n#  MAGNUM_TARGET_HEADLESS       - Defined if compiled for headless machines\n#  MAGNUM_TARGET_VK             - Defined if compiled with Vulkan interop\n#\n# The following variables are provided for backwards compatibility purposes\n# only when MAGNUM_BUILD_DEPRECATED is enabled and will be removed in a future\n# release:\n#\n#  MAGNUM_BUILD_MULTITHREADED   - Alias to CORRADE_BUILD_MULTITHREADED. Use\n#   CORRADE_BUILD_MULTITHREADED instead.\n#\n# Additionally these variables are defined for internal usage:\n#\n#  MAGNUM_INCLUDE_DIR           - Root include dir (w/o dependencies)\n#  MAGNUM_LIBRARY               - Magnum library (w/o dependencies)\n#  MAGNUM_LIBRARY_DEBUG         - Debug version of Magnum library, if found\n#  MAGNUM_LIBRARY_RELEASE       - Release version of Magnum library, if found\n#  MAGNUM_*_LIBRARY             - Component libraries (w/o dependencies)\n#  MAGNUM_*_LIBRARY_DEBUG       - Debug version of given library, if found\n#  MAGNUM_*_LIBRARY_RELEASE     - Release version of given library, if found\n#  MAGNUM_BINARY_INSTALL_DIR    - Binary installation directory\n#  MAGNUM_LIBRARY_INSTALL_DIR   - Library installation directory\n#  MAGNUM_DATA_INSTALL_DIR      - Data installation directory\n#  MAGNUM_PLUGINS_[DEBUG|RELEASE]_BINARY_INSTALL_DIR - Plugin binary\n#   installation directory\n#  MAGNUM_PLUGINS_[DEBUG|RELEASE]_LIBRARY_INSTALL_DIR - Plugin library\n#   installation directory\n#  MAGNUM_PLUGINS_FONT_[DEBUG|RELEASE]_BINARY_INSTALL_DIR - Font plugin binary\n#   installation directory\n#  MAGNUM_PLUGINS_FONT_[DEBUG|RELEASE]_LIBRARY_INSTALL_DIR - Font plugin\n#   library installation directory\n#  MAGNUM_PLUGINS_FONTCONVERTER_[DEBUG|RELEASE]_BINARY_INSTALL_DIR - Font\n#   converter plugin binary installation directory\n#  MAGNUM_PLUGINS_FONTCONVERTER_[DEBUG|RELEASE]_LIBRARY_INSTALL_DIR - Font\n#   converter plugin library installation directory\n#  MAGNUM_PLUGINS_IMAGECONVERTER_[DEBUG|RELEASE]_BINARY_INSTALL_DIR - Image\n#   converter plugin binary installation directory\n#  MAGNUM_PLUGINS_IMAGECONVERTER_[DEBUG|RELEASE]_LIBRARY_INSTALL_DIR - Image\n#   converter plugin library installation directory\n#  MAGNUM_PLUGINS_IMPORTER_[DEBUG|RELEASE]_BINARY_INSTALL_DIR  - Importer\n#   plugin binary installation directory\n#  MAGNUM_PLUGINS_IMPORTER_[DEBUG|RELEASE]_LIBRARY_INSTALL_DIR  - Importer\n#   plugin library installation directory\n#  MAGNUM_PLUGINS_AUDIOIMPORTER_[DEBUG|RELEASE]_BINARY_INSTALL_DIR - Audio\n#   importer plugin binary installation directory\n#  MAGNUM_PLUGINS_AUDIOIMPORTER_[DEBUG|RELEASE]_LIBRARY_INSTALL_DIR - Audio\n#   importer plugin library installation directory\n#  MAGNUM_INCLUDE_INSTALL_DIR   - Header installation directory\n#  MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR - Plugin header installation directory\n#\n\n#\n#   This file is part of Magnum.\n#\n#   Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019\n#             Vladimír Vondruš <mosra@centrum.cz>\n#\n#   Permission is hereby granted, free of charge, to any person obtaining a\n#   copy of this software and associated documentation files (the \"Software\"),\n#   to deal in the Software without restriction, including without limitation\n#   the rights to use, copy, modify, merge, publish, distribute, sublicense,\n#   and/or sell copies of the Software, and to permit persons to whom the\n#   Software is furnished to do so, subject to the following conditions:\n#\n#   The above copyright notice and this permission notice shall be included\n#   in all copies or substantial portions of the Software.\n#\n#   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#   DEALINGS IN THE SOFTWARE.\n#\n\n# Corrade library dependencies\nset(_MAGNUM_CORRADE_DEPENDENCIES )\nforeach(_component ${Magnum_FIND_COMPONENTS})\n    string(TOUPPER ${_component} _COMPONENT)\n\n    # Unrolling the transitive dependencies here so this doesn't need to be\n    # after resolving inter-component dependencies. Listing also all plugins.\n    if(_component MATCHES \"^(Audio|DebugTools|MeshTools|Primitives|Text|TextureTools|Trade|.+Importer|.+ImageConverter|.+Font)$\")\n        set(_MAGNUM_${_COMPONENT}_CORRADE_DEPENDENCIES PluginManager)\n    endif()\n\n    list(APPEND _MAGNUM_CORRADE_DEPENDENCIES ${_MAGNUM_${_COMPONENT}_CORRADE_DEPENDENCIES})\nendforeach()\nfind_package(Corrade REQUIRED Utility ${_MAGNUM_CORRADE_DEPENDENCIES})\n\n# Root include dir\nfind_path(MAGNUM_INCLUDE_DIR\n    NAMES Magnum/Magnum.h)\nmark_as_advanced(MAGNUM_INCLUDE_DIR)\n\n# Configuration file\nfind_file(_MAGNUM_CONFIGURE_FILE configure.h\n    HINTS ${MAGNUM_INCLUDE_DIR}/Magnum/)\nmark_as_advanced(_MAGNUM_CONFIGURE_FILE)\n\n# We need to open configure.h file from MAGNUM_INCLUDE_DIR before we check for\n# the components. Bail out with proper error message if it wasn't found. The\n# complete check with all components is further below.\nif(NOT MAGNUM_INCLUDE_DIR)\n    include(FindPackageHandleStandardArgs)\n    find_package_handle_standard_args(Magnum\n        REQUIRED_VARS MAGNUM_INCLUDE_DIR _MAGNUM_CONFIGURE_FILE)\nendif()\n\n# Read flags from configuration\nfile(READ ${_MAGNUM_CONFIGURE_FILE} _magnumConfigure)\nset(_magnumFlags\n    # WARNING: CAREFUL HERE, the string(FIND) succeeds even if a subset is\n    # found -- so e.g. looking for TARGET_GL will match TARGET_GLES2 as well.\n    # So far that's not a problem, but might become an issue for new flags.\n    BUILD_DEPRECATED\n    BUILD_STATIC\n    TARGET_GL\n    TARGET_GLES\n    TARGET_GLES2\n    TARGET_GLES3\n    TARGET_DESKTOP_GLES\n    TARGET_WEBGL\n    TARGET_HEADLESS\n    TARGET_VK)\nforeach(_magnumFlag ${_magnumFlags})\n    string(FIND \"${_magnumConfigure}\" \"#define MAGNUM_${_magnumFlag}\" _magnum_${_magnumFlag})\n    if(NOT _magnum_${_magnumFlag} EQUAL -1)\n        set(MAGNUM_${_magnumFlag} 1)\n    endif()\nendforeach()\n\n# For compatibility only, to be removed at some point\nif(MAGNUM_BUILD_DEPRECATED AND CORRADE_BUILD_MULTITHREADED)\n    set(MAGNUM_BUILD_MULTITHREADED 1)\nendif()\n\n# OpenGL library preference. Prefer to use GLVND, since that's the better\n# approach nowadays, but allow the users to override it from outside in case\n# it is broken for some reason (Nvidia drivers in Debian's testing (Buster) --\n# reported on 2019-04-09).\nif(NOT CMAKE_VERSION VERSION_LESS 3.10 AND NOT OpenGL_GL_PREFERENCE)\n    set(OpenGL_GL_PREFERENCE GLVND)\nendif()\n\n# Base Magnum library\nif(NOT TARGET Magnum::Magnum)\n    add_library(Magnum::Magnum UNKNOWN IMPORTED)\n\n    # Try to find both debug and release version\n    find_library(MAGNUM_LIBRARY_DEBUG Magnum-d)\n    find_library(MAGNUM_LIBRARY_RELEASE Magnum)\n    mark_as_advanced(MAGNUM_LIBRARY_DEBUG\n        MAGNUM_LIBRARY_RELEASE)\n\n    # Set the MAGNUM_LIBRARY variable based on what was found, use that\n    # information to guess also build type of dynamic plugins\n    if(MAGNUM_LIBRARY_DEBUG AND MAGNUM_LIBRARY_RELEASE)\n        set(MAGNUM_LIBRARY ${MAGNUM_LIBRARY_RELEASE})\n        get_filename_component(_MAGNUM_PLUGINS_DIR_PREFIX ${MAGNUM_LIBRARY_DEBUG} PATH)\n        if(CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n            set(_MAGNUM_PLUGINS_DIR_SUFFIX \"-d\")\n        endif()\n    elseif(MAGNUM_LIBRARY_DEBUG)\n        set(MAGNUM_LIBRARY ${MAGNUM_LIBRARY_DEBUG})\n        get_filename_component(_MAGNUM_PLUGINS_DIR_PREFIX ${MAGNUM_LIBRARY_DEBUG} PATH)\n        set(_MAGNUM_PLUGINS_DIR_SUFFIX \"-d\")\n    elseif(MAGNUM_LIBRARY_RELEASE)\n        set(MAGNUM_LIBRARY ${MAGNUM_LIBRARY_RELEASE})\n        get_filename_component(_MAGNUM_PLUGINS_DIR_PREFIX ${MAGNUM_LIBRARY_RELEASE} PATH)\n    endif()\n\n    # On DLL platforms the plugins are stored in bin/ instead of lib/, modify\n    # _MAGNUM_PLUGINS_DIR_PREFIX accordingly\n    if(CORRADE_TARGET_WINDOWS)\n        get_filename_component(_MAGNUM_PLUGINS_DIR_PREFIX ${_MAGNUM_PLUGINS_DIR_PREFIX} PATH)\n        set(_MAGNUM_PLUGINS_DIR_PREFIX ${_MAGNUM_PLUGINS_DIR_PREFIX}/bin)\n    endif()\n\n    if(MAGNUM_LIBRARY_RELEASE)\n        set_property(TARGET Magnum::Magnum APPEND PROPERTY\n            IMPORTED_CONFIGURATIONS RELEASE)\n        set_property(TARGET Magnum::Magnum PROPERTY\n            IMPORTED_LOCATION_RELEASE ${MAGNUM_LIBRARY_RELEASE})\n    endif()\n\n    if(MAGNUM_LIBRARY_DEBUG)\n        set_property(TARGET Magnum::Magnum APPEND PROPERTY\n            IMPORTED_CONFIGURATIONS DEBUG)\n        set_property(TARGET Magnum::Magnum PROPERTY\n            IMPORTED_LOCATION_DEBUG ${MAGNUM_LIBRARY_DEBUG})\n    endif()\n\n    # Include directories\n    set_property(TARGET Magnum::Magnum APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES\n        ${MAGNUM_INCLUDE_DIR})\n    # Some deprecated APIs use headers (but not externally defined symbols)\n    # from the GL library, link those includes as well\n    if(MAGNUM_BUILD_DEPRECATED AND MAGNUM_TARGET_GL)\n        set_property(TARGET Magnum::Magnum APPEND PROPERTY\n            INTERFACE_INCLUDE_DIRECTORIES ${MAGNUM_INCLUDE_DIR}/MagnumExternal/OpenGL)\n    endif()\n\n    # Dependent libraries\n    set_property(TARGET Magnum::Magnum APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n         Corrade::Utility)\nelse()\n    set(MAGNUM_LIBRARY Magnum::Magnum)\nendif()\n\n# Component distinction (listing them explicitly to avoid mistakes with finding\n# components from other repositories)\nset(_MAGNUM_LIBRARY_COMPONENT_LIST\n    Audio DebugTools GL MeshTools Primitives SceneGraph Shaders Text\n    TextureTools Trade Vk\n    AndroidApplication EmscriptenApplication GlfwApplication GlxApplication\n    Sdl2Application XEglApplication WindowlessCglApplication\n    WindowlessEglApplication WindowlessGlxApplication WindowlessIosApplication\n    WindowlessWglApplication WindowlessWindowsEglApplication\n    CglContext EglContext GlxContext WglContext\n    OpenGLTester)\nset(_MAGNUM_PLUGIN_COMPONENT_LIST\n    AnyAudioImporter AnyImageConverter AnyImageImporter AnySceneImporter\n    MagnumFont MagnumFontConverter ObjImporter TgaImageConverter TgaImporter\n    WavAudioImporter)\nset(_MAGNUM_EXECUTABLE_COMPONENT_LIST\n    distancefieldconverter fontconverter imageconverter gl-info al-info)\n\n# Inter-component dependencies\nset(_MAGNUM_Audio_DEPENDENCIES )\n\nset(_MAGNUM_DebugTools_DEPENDENCIES )\nif(MAGNUM_TARGET_GL)\n    # MeshTools, Primitives, SceneGraph and Shaders are used only for GL\n    # renderers. All of this is optional, compiled in only if the base library\n    # was selected.\n    list(APPEND _MAGNUM_DebugTools_DEPENDENCIES MeshTools Primitives SceneGraph Shaders Trade GL)\n    set(_MAGNUM_DebugTools_MeshTools_DEPENDENCY_IS_OPTIONAL ON)\n    set(_MAGNUM_DebugTools_Primitives_DEPENDENCY_IS_OPTIONAL ON)\n    set(_MAGNUM_DebugTools_SceneGraph_DEPENDENCY_IS_OPTIONAL ON)\n    set(_MAGNUM_DebugTools_Shaders_DEPENDENCY_IS_OPTIONAL ON)\n    set(_MAGNUM_DebugTools_Trade_DEPENDENCY_IS_OPTIONAL ON)\n    set(_MAGNUM_DebugTools_GL_DEPENDENCY_IS_OPTIONAL ON)\nendif()\n\nset(_MAGNUM_MeshTools_DEPENDENCIES )\nif(MAGNUM_TARGET_GL)\n    # Trade is used only in compile(), which needs GL as well\n    list(APPEND _MAGNUM_MeshTools_DEPENDENCIES Trade GL)\nendif()\n\nset(_MAGNUM_OpenGLTester_DEPENDENCIES GL)\nif(MAGNUM_TARGET_HEADLESS OR CORRADE_TARGET_EMSCRIPTEN OR CORRADE_TARGET_ANDROID)\n    list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessEglApplication)\nelseif(CORRADE_TARGET_IOS)\n    list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessIosApplication)\nelseif(CORRADE_TARGET_APPLE)\n    list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessCglApplication)\nelseif(CORRADE_TARGET_UNIX)\n    if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES)\n        list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessEglApplication)\n    else()\n        list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessGlxApplication)\n    endif()\nelseif(CORRADE_TARGET_WINDOWS)\n    if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES)\n        list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessWglApplication)\n    else()\n        list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessWindowsEglApplication)\n    endif()\nendif()\n\nset(_MAGNUM_Primitives_DEPENDENCIES Trade)\nset(_MAGNUM_SceneGraph_DEPENDENCIES )\nset(_MAGNUM_Shaders_DEPENDENCIES GL)\nset(_MAGNUM_Text_DEPENDENCIES TextureTools)\nif(MAGNUM_TARGET_GL)\n    list(APPEND _MAGNUM_Text_DEPENDENCIES GL)\nendif()\n\nset(_MAGNUM_TextureTools_DEPENDENCIES )\nif(MAGNUM_TARGET_GL)\n    list(APPEND _MAGNUM_TextureTools_DEPENDENCIES GL)\nendif()\n\nset(_MAGNUM_Trade_DEPENDENCIES )\nset(_MAGNUM_AndroidApplication_DEPENDENCIES GL)\nset(_MAGNUM_EmscriptenApplication_DEPENDENCIES)\nif(MAGNUM_TARGET_GL)\n    list(APPEND _MAGNUM_EmscriptenApplication_DEPENDENCIES GL)\nendif()\n\nset(_MAGNUM_GlfwApplication_DEPENDENCIES )\nif(MAGNUM_TARGET_GL)\n    list(APPEND _MAGNUM_GlfwApplication_DEPENDENCIES GL)\nendif()\n\nset(_MAGNUM_GlxApplication_DEPENDENCIES GL)\n\nset(_MAGNUM_Sdl2Application_DEPENDENCIES )\nif(MAGNUM_TARGET_GL)\n    list(APPEND _MAGNUM_Sdl2Application_DEPENDENCIES GL)\nendif()\n\nset(_MAGNUM_WindowlessCglApplication_DEPENDENCIES GL)\nset(_MAGNUM_WindowlessEglApplication_DEPENDENCIES GL)\nset(_MAGNUM_WindowlessGlxApplication_DEPENDENCIES GL)\nset(_MAGNUM_WindowlessIosApplication_DEPENDENCIES GL)\nset(_MAGNUM_WindowlessWglApplication_DEPENDENCIES GL)\nset(_MAGNUM_WindowlessWindowsEglApplication_DEPENDENCIES GL)\nset(_MAGNUM_XEglApplication_DEPENDENCIES GL)\nset(_MAGNUM_CglContext_DEPENDENCIES GL)\nset(_MAGNUM_EglContext_DEPENDENCIES GL)\nset(_MAGNUM_GlxContext_DEPENDENCIES GL)\nset(_MAGNUM_WglContext_DEPENDENCIES GL)\n\nset(_MAGNUM_MagnumFont_DEPENDENCIES Trade TgaImporter GL) # and below\nset(_MAGNUM_MagnumFontConverter_DEPENDENCIES Trade TgaImageConverter) # and below\nset(_MAGNUM_ObjImporter_DEPENDENCIES MeshTools) # and below\nforeach(_component ${_MAGNUM_PLUGIN_COMPONENT_LIST})\n    if(_component MATCHES \".+AudioImporter\")\n        list(APPEND _MAGNUM_${_component}_DEPENDENCIES Audio)\n    elseif(_component MATCHES \".+(Importer|ImageConverter)\")\n        list(APPEND _MAGNUM_${_component}_DEPENDENCIES Trade)\n    elseif(_component MATCHES \".+(Font|FontConverter)\")\n        list(APPEND _MAGNUM_${_component}_DEPENDENCIES Text TextureTools)\n    endif()\nendforeach()\n\n# Ensure that all inter-component dependencies are specified as well\nset(_MAGNUM_ADDITIONAL_COMPONENTS )\nforeach(_component ${Magnum_FIND_COMPONENTS})\n    # Mark the dependencies as required if the component is also required, but\n    # only if they themselves are not optional (for example parts of DebugTools\n    # are present only if their respective base library is compiled)\n    if(Magnum_FIND_REQUIRED_${_component})\n        foreach(_dependency ${_MAGNUM_${_component}_DEPENDENCIES})\n            if(NOT _MAGNUM_${_component}_${_dependency}_DEPENDENCY_IS_OPTIONAL)\n                set(Magnum_FIND_REQUIRED_${_dependency} TRUE)\n            endif()\n        endforeach()\n    endif()\n\n    list(APPEND _MAGNUM_ADDITIONAL_COMPONENTS ${_MAGNUM_${_component}_DEPENDENCIES})\nendforeach()\n\n# Join the lists, remove duplicate components\nif(_MAGNUM_ADDITIONAL_COMPONENTS)\n    list(INSERT Magnum_FIND_COMPONENTS 0 ${_MAGNUM_ADDITIONAL_COMPONENTS})\nendif()\nif(Magnum_FIND_COMPONENTS)\n    list(REMOVE_DUPLICATES Magnum_FIND_COMPONENTS)\nendif()\n\n# Convert components lists to regular expressions so I can use if(MATCHES).\n# TODO: Drop this once CMake 3.3 and if(IN_LIST) can be used\nforeach(_WHAT LIBRARY PLUGIN EXECUTABLE)\n    string(REPLACE \";\" \"|\" _MAGNUM_${_WHAT}_COMPONENTS \"${_MAGNUM_${_WHAT}_COMPONENT_LIST}\")\n    set(_MAGNUM_${_WHAT}_COMPONENTS \"^(${_MAGNUM_${_WHAT}_COMPONENTS})$\")\nendforeach()\n\n# Find all components. Maintain a list of components that'll need to have\n# their optional dependencies checked.\nset(_MAGNUM_OPTIONAL_DEPENDENCIES_TO_ADD )\nforeach(_component ${Magnum_FIND_COMPONENTS})\n    string(TOUPPER ${_component} _COMPONENT)\n\n    # Create imported target in case the library is found. If the project is\n    # added as subproject to CMake, the target already exists and all the\n    # required setup is already done from the build tree.\n    if(TARGET Magnum::${_component})\n        set(Magnum_${_component}_FOUND TRUE)\n    else()\n        # Library components\n        if(_component MATCHES ${_MAGNUM_LIBRARY_COMPONENTS})\n            add_library(Magnum::${_component} UNKNOWN IMPORTED)\n\n            # Set library defaults, find the library\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/${_component})\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES ${_component}.h)\n\n            # Try to find both debug and release version\n            find_library(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG Magnum${_component}-d)\n            find_library(MAGNUM_${_COMPONENT}_LIBRARY_RELEASE Magnum${_component})\n            mark_as_advanced(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG\n                MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)\n        endif()\n\n        # Plugin components\n        if(_component MATCHES ${_MAGNUM_PLUGIN_COMPONENTS})\n            add_library(Magnum::${_component} UNKNOWN IMPORTED)\n\n            # AudioImporter plugin specific name suffixes\n            if(_component MATCHES \".+AudioImporter$\")\n                set(_MAGNUM_${_COMPONENT}_PATH_SUFFIX audioimporters)\n\n                # Audio importer class is Audio::*Importer, thus we need to\n                # convert *AudioImporter.h to *Importer.h\n                string(REPLACE \"AudioImporter\" \"Importer\" _MAGNUM_${_COMPONENT}_HEADER_NAME \"${_component}\")\n                set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES ${_MAGNUM_${_COMPONENT}_HEADER_NAME}.h)\n\n            # Importer plugin specific name suffixes\n            elseif(_component MATCHES \".+Importer$\")\n                set(_MAGNUM_${_COMPONENT}_PATH_SUFFIX importers)\n\n            # Font plugin specific name suffixes\n            elseif(_component MATCHES \".+Font$\")\n                set(_MAGNUM_${_COMPONENT}_PATH_SUFFIX fonts)\n\n            # ImageConverter plugin specific name suffixes\n            elseif(_component MATCHES \".+ImageConverter$\")\n                set(_MAGNUM_${_COMPONENT}_PATH_SUFFIX imageconverters)\n\n            # FontConverter plugin specific name suffixes\n            elseif(_component MATCHES \".+FontConverter$\")\n                set(_MAGNUM_${_COMPONENT}_PATH_SUFFIX fontconverters)\n            endif()\n\n            # Don't override the exception for *AudioImporter plugins\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX MagnumPlugins/${_component})\n            if(NOT _MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES)\n                set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES ${_component}.h)\n            endif()\n\n            # Dynamic plugins don't have any prefix (e.g. `lib` on Linux),\n            # search with empty prefix and then reset that back so we don't\n            # accidentaly break something else\n            set(_tmp_prefixes \"${CMAKE_FIND_LIBRARY_PREFIXES}\")\n            set(CMAKE_FIND_LIBRARY_PREFIXES \"${CMAKE_FIND_LIBRARY_PREFIXES};\")\n\n            # Try to find both debug and release version. Dynamic and static\n            # debug libraries are in different places. Static debug plugins are\n            # in magnum/ with a -d suffix while dynamic debug plugins are in\n            # magnum-d/ with no suffix. Problem is that Vcpkg's library linking\n            # automagic needs the static libs to be in the root library\n            # directory along with everything else and so we need to search for\n            # the -d suffixed version *before* the unsuffixed so it doesn't\n            # pick the release library for both debug and release.\n            find_library(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG ${_component}-d\n                PATH_SUFFIXES magnum/${_MAGNUM_${_COMPONENT}_PATH_SUFFIX})\n            find_library(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG ${_component}\n                PATH_SUFFIXES magnum-d/${_MAGNUM_${_COMPONENT}_PATH_SUFFIX})\n            find_library(MAGNUM_${_COMPONENT}_LIBRARY_RELEASE ${_component}\n                PATH_SUFFIXES magnum/${_MAGNUM_${_COMPONENT}_PATH_SUFFIX})\n            mark_as_advanced(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG\n                MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)\n\n            # Reset back\n            set(CMAKE_FIND_LIBRARY_PREFIXES \"${_tmp_prefixes}\")\n        endif()\n\n        # Library location for libraries/plugins\n        if(_component MATCHES ${_MAGNUM_LIBRARY_COMPONENTS} OR _component MATCHES ${_MAGNUM_PLUGIN_COMPONENTS})\n            if(MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    IMPORTED_CONFIGURATIONS RELEASE)\n                set_property(TARGET Magnum::${_component} PROPERTY\n                    IMPORTED_LOCATION_RELEASE ${MAGNUM_${_COMPONENT}_LIBRARY_RELEASE})\n            endif()\n\n            if(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    IMPORTED_CONFIGURATIONS DEBUG)\n                set_property(TARGET Magnum::${_component} PROPERTY\n                    IMPORTED_LOCATION_DEBUG ${MAGNUM_${_COMPONENT}_LIBRARY_DEBUG})\n            endif()\n        endif()\n\n        # Executables\n        if(_component MATCHES ${_MAGNUM_EXECUTABLE_COMPONENTS})\n            add_executable(Magnum::${_component} IMPORTED)\n\n            find_program(MAGNUM_${_COMPONENT}_EXECUTABLE magnum-${_component})\n            mark_as_advanced(MAGNUM_${_COMPONENT}_EXECUTABLE)\n\n            if(MAGNUM_${_COMPONENT}_EXECUTABLE)\n                set_property(TARGET Magnum::${_component} PROPERTY\n                    IMPORTED_LOCATION ${MAGNUM_${_COMPONENT}_EXECUTABLE})\n            endif()\n        endif()\n\n        # Applications\n        if(_component MATCHES \".+Application\")\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/Platform)\n\n            # Android application dependencies\n            if(_component STREQUAL AndroidApplication)\n                find_package(EGL)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES android EGL::EGL)\n\n            # EmscriptenApplication has no additional dependencies\n\n            # GLFW application dependencies\n            elseif(_component STREQUAL GlfwApplication)\n                find_package(GLFW)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES GLFW::GLFW)\n                # Use the Foundation framework on Apple to query the DPI awareness\n                if(CORRADE_TARGET_APPLE)\n                    find_library(_MAGNUM_APPLE_FOUNDATION_FRAMEWORK_LIBRARY Foundation)\n                    mark_as_advanced(_MAGNUM_APPLE_FOUNDATION_FRAMEWORK_LIBRARY)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES ${_MAGNUM_APPLE_FOUNDATION_FRAMEWORK_LIBRARY})\n                # Needed for opt-in DPI queries\n                elseif(CORRADE_TARGET_UNIX)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})\n                endif()\n\n                # With GLVND (since CMake 3.11) we need to explicitly link to\n                # GLX/EGL because libOpenGL doesn't provide it. For EGL we have\n                # our own EGL find module, which makes things simpler. The\n                # upstream FindOpenGL is anything but simple. Also can't use\n                # OpenGL_OpenGL_FOUND, because that one is set also if GLVND is\n                # *not* found. WTF. Also can't just check for\n                # OPENGL_opengl_LIBRARY because that's set even if\n                # OpenGL_GL_PREFERENCE is explicitly set to LEGACY.\n                if(MAGNUM_TARGET_GL)\n                    if(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE AND (NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES))\n                        find_package(OpenGL)\n                        if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)\n                            set_property(TARGET Magnum::${_component} APPEND\n                            PROPERTY INTERFACE_LINK_LIBRARIES OpenGL::GLX)\n                        endif()\n                    elseif(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES AND NOT CORRADE_TARGET_EMSCRIPTEN)\n                        find_package(EGL)\n                        set_property(TARGET Magnum::${_component} APPEND\n                            PROPERTY INTERFACE_LINK_LIBRARIES EGL::EGL)\n                    endif()\n                endif()\n\n            # SDL2 application dependencies\n            elseif(_component STREQUAL Sdl2Application)\n                find_package(SDL2)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES SDL2::SDL2)\n                # Use the Foundation framework on Apple to query the DPI awareness\n                if(CORRADE_TARGET_APPLE)\n                    find_library(_MAGNUM_APPLE_FOUNDATION_FRAMEWORK_LIBRARY Foundation)\n                    mark_as_advanced(_MAGNUM_APPLE_FOUNDATION_FRAMEWORK_LIBRARY)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES ${_MAGNUM_APPLE_FOUNDATION_FRAMEWORK_LIBRARY})\n                # Needed for opt-in DPI queries\n                elseif(CORRADE_TARGET_UNIX)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})\n                endif()\n\n                # With GLVND (since CMake 3.11) we need to explicitly link to\n                # GLX/EGL because libOpenGL doesn't provide it. For EGL we have\n                # our own EGL find module, which makes things simpler. The\n                # upstream FindOpenGL is anything but simple. Also can't use\n                # OpenGL_OpenGL_FOUND, because that one is set also if GLVND is\n                # *not* found. WTF. Also can't just check for\n                # OPENGL_opengl_LIBRARY because that's set even if\n                # OpenGL_GL_PREFERENCE is explicitly set to LEGACY.\n                if(MAGNUM_TARGET_GL)\n                    if(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE AND (NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES))\n                        find_package(OpenGL)\n                        if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)\n                            set_property(TARGET Magnum::${_component} APPEND\n                            PROPERTY INTERFACE_LINK_LIBRARIES OpenGL::GLX)\n                        endif()\n                    elseif(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES AND NOT CORRADE_TARGET_EMSCRIPTEN)\n                        find_package(EGL)\n                        set_property(TARGET Magnum::${_component} APPEND\n                            PROPERTY INTERFACE_LINK_LIBRARIES EGL::EGL)\n                    endif()\n                endif()\n\n            # (Windowless) GLX application dependencies\n            elseif(_component STREQUAL GlxApplication OR _component STREQUAL WindowlessGlxApplication)\n                find_package(X11)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_INCLUDE_DIRECTORIES ${X11_INCLUDE_DIR})\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES ${X11_LIBRARIES})\n\n                # With GLVND (since CMake 3.11) we need to explicitly link to\n                # GLX because libOpenGL doesn't provide it. Also can't use\n                # OpenGL_OpenGL_FOUND, because that one is set also if GLVND is\n                # *not* found. WTF. Also can't just check for\n                # OPENGL_opengl_LIBRARY because that's set even if\n                # OpenGL_GL_PREFERENCE is explicitly set to LEGACY.\n                find_package(OpenGL)\n                if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES OpenGL::GLX)\n                endif()\n\n            # Windowless CGL application has no additional dependencies\n\n            # Windowless EGL application dependencies\n            elseif(_component STREQUAL WindowlessEglApplication)\n                find_package(EGL)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES EGL::EGL)\n\n            # Windowless iOS application dependencies\n            elseif(_component STREQUAL WindowlessIosApplication)\n                # We need to link to Foundation framework to use ObjC\n                find_library(_MAGNUM_IOS_FOUNDATION_FRAMEWORK_LIBRARY Foundation)\n                mark_as_advanced(_MAGNUM_IOS_FOUNDATION_FRAMEWORK_LIBRARY)\n                find_package(EGL)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES EGL::EGL ${_MAGNUM_IOS_FOUNDATION_FRAMEWORK_LIBRARY})\n\n            # Windowless WGL application has no additional dependencies\n\n            # Windowless Windows/EGL application dependencies\n            elseif(_component STREQUAL WindowlessWindowsEglApplication)\n                find_package(EGL)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES EGL::EGL)\n\n            # X/EGL application dependencies\n            elseif(_component STREQUAL XEglApplication)\n                find_package(EGL)\n                find_package(X11)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_INCLUDE_DIRECTORIES ${X11_INCLUDE_DIR})\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES EGL::EGL ${X11_LIBRARIES})\n            endif()\n\n        # Context libraries\n        elseif(_component MATCHES \".+Context\")\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/Platform)\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES GLContext.h)\n\n            # GLX context dependencies\n            if(_component STREQUAL GlxContext)\n                # With GLVND (since CMake 3.11) we need to explicitly link to\n                # GLX because libOpenGL doesn't provide it. Also can't use\n                # OpenGL_OpenGL_FOUND, because that one is set also if GLVND is\n                # *not* found. If GLVND is not used, link to X11 instead. Also\n                # can't just check for OPENGL_opengl_LIBRARY because that's set\n                # even if OpenGL_GL_PREFERENCE is explicitly set to LEGACY.\n                find_package(OpenGL)\n                if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES OpenGL::GLX)\n                else()\n                    find_package(X11)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_INCLUDE_DIRECTORIES ${X11_INCLUDE_DIR})\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES ${X11_LIBRARIES})\n                endif()\n\n            # EGL context dependencies\n            elseif(_component STREQUAL EglContext)\n                find_package(EGL)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES EGL::EGL)\n            endif()\n\n            # No additional dependencies for CGL context\n            # No additional dependencies for WGL context\n\n        # Audio library\n        elseif(_component STREQUAL Audio)\n            find_package(OpenAL)\n            set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                INTERFACE_INCLUDE_DIRECTORIES ${OPENAL_INCLUDE_DIR})\n            set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES ${OPENAL_LIBRARY} Corrade::PluginManager)\n\n        # No special setup for DebugTools library\n\n        # GL library\n        elseif(_component STREQUAL GL)\n            if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES)\n                # If the GLVND library (CMake 3.11+) was found, link to the\n                # imported target. Otherwise (and also on all systems except\n                # Linux) link to the classic libGL. Can't use\n                # OpenGL_OpenGL_FOUND, because that one is set also if GLVND is\n                # *not* found. WTF. Also can't just check for\n                # OPENGL_opengl_LIBRARY because that's set even if\n                # OpenGL_GL_PREFERENCE is explicitly set to LEGACY.\n                find_package(OpenGL REQUIRED)\n                if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES OpenGL::OpenGL)\n                else()\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES ${OPENGL_gl_LIBRARY})\n                endif()\n            elseif(MAGNUM_TARGET_GLES2)\n                find_package(OpenGLES2 REQUIRED)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES OpenGLES2::OpenGLES2)\n            elseif(MAGNUM_TARGET_GLES3)\n                find_package(OpenGLES3 REQUIRED)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES OpenGLES3::OpenGLES3)\n            endif()\n\n        # MeshTools library\n        elseif(_component STREQUAL MeshTools)\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES CompressIndices.h)\n\n        # OpenGLTester library\n        elseif(_component STREQUAL OpenGLTester)\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/GL)\n\n        # Primitives library\n        elseif(_component STREQUAL Primitives)\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Cube.h)\n\n        # No special setup for SceneGraph library\n        # No special setup for Shaders library\n\n        # Text library\n        elseif(_component STREQUAL Text)\n            set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES Corrade::PluginManager)\n\n        # TextureTools library\n        elseif(_component STREQUAL TextureTools)\n            set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Atlas.h)\n\n        # Trade library\n        elseif(_component STREQUAL Trade)\n            set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES Corrade::PluginManager)\n\n        # Vk library\n        elseif(_component STREQUAL Vk)\n            set(Vulkan_INCLUDE_DIR ${MAGNUM_INCLUDE_DIR}/MagnumExternal/Vulkan)\n            find_package(Vulkan REQUIRED)\n            set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES Vulkan::Vulkan)\n        endif()\n\n        # No special setup for AnyAudioImporter plugin\n        # No special setup for AnyImageConverter plugin\n        # No special setup for AnyImageImporter plugin\n        # No special setup for AnySceneImporter plugin\n        # No special setup for MagnumFont plugin\n        # No special setup for MagnumFontConverter plugin\n        # No special setup for ObjImporter plugin\n        # No special setup for TgaImageConverter plugin\n        # No special setup for TgaImporter plugin\n        # No special setup for WavAudioImporter plugin\n\n        # Find library/plugin includes\n        if(_component MATCHES ${_MAGNUM_LIBRARY_COMPONENTS} OR _component MATCHES ${_MAGNUM_PLUGIN_COMPONENTS})\n            find_path(_MAGNUM_${_COMPONENT}_INCLUDE_DIR\n                NAMES ${_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES}\n                HINTS ${MAGNUM_INCLUDE_DIR}/${_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX})\n            mark_as_advanced(_MAGNUM_${_COMPONENT}_INCLUDE_DIR)\n        endif()\n\n        # Automatic import of static plugins. Skip in case the include dir was\n        # not found -- that'll fail later with a proper message.\n        if(_component MATCHES ${_MAGNUM_PLUGIN_COMPONENTS} AND _MAGNUM_${_COMPONENT}_INCLUDE_DIR)\n            # Automatic import of static plugins\n            file(READ ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/configure.h _magnum${_component}Configure)\n            string(FIND \"${_magnum${_component}Configure}\" \"#define MAGNUM_${_COMPONENT}_BUILD_STATIC\" _magnum${_component}_BUILD_STATIC)\n            if(NOT _magnum${_component}_BUILD_STATIC EQUAL -1)\n                set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                    INTERFACE_SOURCES ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/importStaticPlugin.cpp)\n            endif()\n        endif()\n\n        # Link to core Magnum library, add inter-library dependencies. If there\n        # are optional dependencies, defer adding them to later once we know if\n        # they were found or not.\n        if(_component MATCHES ${_MAGNUM_LIBRARY_COMPONENTS} OR _component MATCHES ${_MAGNUM_PLUGIN_COMPONENTS})\n            set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES Magnum::Magnum)\n            set(_MAGNUM_${component}_OPTIONAL_DEPENDENCIES_TO_ADD )\n            foreach(_dependency ${_MAGNUM_${_component}_DEPENDENCIES})\n                if(NOT _MAGNUM_${_component}_${_dependency}_DEPENDENCY_IS_OPTIONAL)\n                    set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES Magnum::${_dependency})\n                else()\n                    list(APPEND _MAGNUM_${_component}_OPTIONAL_DEPENDENCIES_TO_ADD\n                        ${_dependency})\n                endif()\n            endforeach()\n            if(_MAGNUM_${_component}_OPTIONAL_DEPENDENCIES_TO_ADD)\n                list(APPEND _MAGNUM_OPTIONAL_DEPENDENCIES_TO_ADD ${_component})\n            endif()\n        endif()\n\n        # Decide if the library was found\n        if(((_component MATCHES ${_MAGNUM_LIBRARY_COMPONENTS} OR _component MATCHES ${_MAGNUM_PLUGIN_COMPONENTS}) AND _MAGNUM_${_COMPONENT}_INCLUDE_DIR AND (MAGNUM_${_COMPONENT}_LIBRARY_DEBUG OR MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)) OR (_component MATCHES ${_MAGNUM_EXECUTABLE_COMPONENTS} AND MAGNUM_${_COMPONENT}_EXECUTABLE))\n            set(Magnum_${_component}_FOUND TRUE)\n        else()\n            set(Magnum_${_component}_FOUND FALSE)\n        endif()\n    endif()\n\n    # Global aliases for Windowless*Application, *Application and *Context\n    # components. If already set, unset them to avoid ambiguity.\n    if(_component MATCHES \"Windowless.+Application\")\n        if(NOT DEFINED _MAGNUM_WINDOWLESSAPPLICATION_ALIAS)\n            set(_MAGNUM_WINDOWLESSAPPLICATION_ALIAS Magnum::${_component})\n        else()\n            unset(_MAGNUM_WINDOWLESSAPPLICATION_ALIAS)\n        endif()\n    elseif(_component MATCHES \".+Application\")\n        if(NOT DEFINED _MAGNUM_APPLICATION_ALIAS)\n            set(_MAGNUM_APPLICATION_ALIAS Magnum::${_component})\n        else()\n            unset(_MAGNUM_APPLICATION_ALIAS)\n        endif()\n    elseif(_component MATCHES \".+Context\")\n        if(NOT DEFINED _MAGNUM_GLCONTEXT_ALIAS)\n            set(_MAGNUM_GLCONTEXT_ALIAS Magnum::${_component})\n        else()\n            unset(_MAGNUM_GLCONTEXT_ALIAS)\n        endif()\n    endif()\nendforeach()\n\n# Emscripten-specific files and flags\nif(CORRADE_TARGET_EMSCRIPTEN)\n    find_file(MAGNUM_EMSCRIPTENAPPLICATION_JS EmscriptenApplication.js\n        PATH_SUFFIXES share/magnum)\n    find_file(MAGNUM_WINDOWLESSEMSCRIPTENAPPLICATION_JS WindowlessEmscriptenApplication.js\n        PATH_SUFFIXES share/magnum)\n    find_file(MAGNUM_WEBAPPLICATION_CSS WebApplication.css\n        PATH_SUFFIXES share/magnum)\n    mark_as_advanced(\n        MAGNUM_EMSCRIPTENAPPLICATION_JS\n        MAGNUM_WINDOWLESSEMSCRIPTENAPPLICATION_JS\n        MAGNUM_WEBAPPLICATION_CSS)\n    set(MAGNUM_EXTRAS_NEEDED\n        MAGNUM_EMSCRIPTENAPPLICATION_JS\n        MAGNUM_WINDOWLESSEMSCRIPTENAPPLICATION_JS\n        MAGNUM_WEBAPPLICATION_CSS)\n\n    # If we are on CMake 3.13 and up, `-s USE_WEBGL2=1` linker option is\n    # propagated from FindOpenGLES3.cmake already. If not (and the GL library\n    # is used), we need to modify the global CMAKE_EXE_LINKER_FLAGS. Do it here\n    # instead of in FindOpenGLES3.cmake so it works also for CMake subprojects\n    # (in which case find_package(OpenGLES3) is called in (and so\n    # CMAKE_EXE_LINKER_FLAGS would be modified in) Magnum's root CMakeLists.txt\n    # and thus can't affect the variable in the outer project). CMake supports\n    # IN_LIST as an operator since 3.1 (Emscripten needs at least 3.7), but\n    # it's behind a policy, so enable that one as well.\n    cmake_policy(SET CMP0057 NEW)\n    if(CMAKE_VERSION VERSION_LESS 3.13 AND GL IN_LIST Magnum_FIND_COMPONENTS AND NOT MAGNUM_TARGET_GLES2 AND NOT CMAKE_EXE_LINKER_FLAGS MATCHES \"-s USE_WEBGL2=1\")\n        set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -s USE_WEBGL2=1\")\n    endif()\nendif()\n\n# Complete the check with also all components\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(Magnum\n    REQUIRED_VARS MAGNUM_INCLUDE_DIR MAGNUM_LIBRARY ${MAGNUM_EXTRAS_NEEDED}\n    HANDLE_COMPONENTS)\n\n# Components with optional dependencies -- add them once we know if they were\n# found or not.\nforeach(_component ${_MAGNUM_OPTIONAL_DEPENDENCIES_TO_ADD})\n    foreach(_dependency ${_MAGNUM_${_component}_OPTIONAL_DEPENDENCIES_TO_ADD})\n        if(Magnum_${_dependency}_FOUND)\n            set_property(TARGET Magnum::${_component} APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES Magnum::${_dependency})\n        endif()\n    endforeach()\nendforeach()\n\n# Create Windowless*Application, *Application and *Context aliases\n# TODO: ugh why can't I make an alias of IMPORTED target?\nif(_MAGNUM_WINDOWLESSAPPLICATION_ALIAS AND NOT TARGET Magnum::WindowlessApplication)\n    get_target_property(_MAGNUM_WINDOWLESSAPPLICATION_ALIASED_TARGET ${_MAGNUM_WINDOWLESSAPPLICATION_ALIAS} ALIASED_TARGET)\n    if(_MAGNUM_WINDOWLESSAPPLICATION_ALIASED_TARGET)\n        add_library(Magnum::WindowlessApplication ALIAS ${_MAGNUM_WINDOWLESSAPPLICATION_ALIASED_TARGET})\n    else()\n        add_library(Magnum::WindowlessApplication UNKNOWN IMPORTED)\n        foreach(property IMPORTED_CONFIGURATIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS INTERFACE_LINK_LIBRARIES)\n            get_target_property(_MAGNUM_WINDOWLESSAPPLICATION_${property} ${_MAGNUM_WINDOWLESSAPPLICATION_ALIAS} ${property})\n            if(_MAGNUM_WINDOWLESSAPPLICATION_${property})\n                set_target_properties(Magnum::WindowlessApplication PROPERTIES\n                    ${property} \"${_MAGNUM_WINDOWLESSAPPLICATION_${property}}\")\n            endif()\n        endforeach()\n        get_target_property(_MAGNUM_WINDOWLESSAPPLICATION_IMPORTED_LOCATION_RELEASE ${_MAGNUM_WINDOWLESSAPPLICATION_ALIAS} IMPORTED_LOCATION_RELEASE)\n        get_target_property(_MAGNUM_WINDOWLESSAPPLICATION_IMPORTED_LOCATION_DEBUG ${_MAGNUM_WINDOWLESSAPPLICATION_ALIAS} IMPORTED_LOCATION_DEBUG)\n        if(_MAGNUM_WINDOWLESSAPPLICATION_IMPORTED_LOCATION_RELEASE)\n            set_target_properties(Magnum::WindowlessApplication PROPERTIES\n                IMPORTED_LOCATION_RELEASE ${_MAGNUM_WINDOWLESSAPPLICATION_IMPORTED_LOCATION_RELEASE})\n        endif()\n        if(_MAGNUM_WINDOWLESSAPPLICATION_IMPORTED_LOCATION_DEBUG)\n            set_target_properties(Magnum::WindowlessApplication PROPERTIES\n                IMPORTED_LOCATION_DEBUG ${_MAGNUM_WINDOWLESSAPPLICATION_IMPORTED_LOCATION_DEBUG})\n        endif()\n    endif()\n    # Prevent creating the alias again\n    unset(_MAGNUM_WINDOWLESSAPPLICATION_ALIAS)\nendif()\nif(_MAGNUM_APPLICATION_ALIAS AND NOT TARGET Magnum::Application)\n    get_target_property(_MAGNUM_APPLICATION_ALIASED_TARGET ${_MAGNUM_APPLICATION_ALIAS} ALIASED_TARGET)\n    if(_MAGNUM_APPLICATION_ALIASED_TARGET)\n        add_library(Magnum::Application ALIAS ${_MAGNUM_APPLICATION_ALIASED_TARGET})\n    else()\n        add_library(Magnum::Application UNKNOWN IMPORTED)\n        foreach(property IMPORTED_CONFIGURATIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS INTERFACE_LINK_LIBRARIES)\n            get_target_property(_MAGNUM_APPLICATION_${property}\n                ${_MAGNUM_APPLICATION_ALIAS} ${property})\n            if(_MAGNUM_APPLICATION_${property})\n                set_target_properties(Magnum::Application PROPERTIES ${property}\n                    \"${_MAGNUM_APPLICATION_${property}}\")\n            endif()\n        endforeach()\n        get_target_property(_MAGNUM_APPLICATION_IMPORTED_LOCATION_RELEASE ${_MAGNUM_APPLICATION_ALIAS} IMPORTED_LOCATION_RELEASE)\n        get_target_property(_MAGNUM_APPLICATION_IMPORTED_LOCATION_DEBUG ${_MAGNUM_APPLICATION_ALIAS} IMPORTED_LOCATION_DEBUG)\n        if(_MAGNUM_APPLICATION_IMPORTED_LOCATION_RELEASE)\n            set_target_properties(Magnum::Application PROPERTIES\n                IMPORTED_LOCATION_RELEASE ${_MAGNUM_APPLICATION_IMPORTED_LOCATION_RELEASE})\n        endif()\n        if(_MAGNUM_APPLICATION_IMPORTED_LOCATION_DEBUG)\n            set_target_properties(Magnum::Application PROPERTIES\n                IMPORTED_LOCATION_DEBUG ${_MAGNUM_APPLICATION_IMPORTED_LOCATION_DEBUG})\n        endif()\n    endif()\n    # Prevent creating the alias again\n    unset(_MAGNUM_APPLICATION_ALIAS)\nendif()\nif(_MAGNUM_GLCONTEXT_ALIAS AND NOT TARGET Magnum::GLContext)\n    get_target_property(_MAGNUM_GLCONTEXT_ALIASED_TARGET ${_MAGNUM_GLCONTEXT_ALIAS} ALIASED_TARGET)\n    if(_MAGNUM_GLCONTEXT_ALIASED_TARGET)\n        add_library(Magnum::GLContext ALIAS ${_MAGNUM_GLCONTEXT_ALIASED_TARGET})\n    else()\n        add_library(Magnum::GLContext UNKNOWN IMPORTED)\n        foreach(property IMPORTED_CONFIGURATIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS INTERFACE_LINK_LIBRARIES)\n            get_target_property(_MAGNUM_GLCONTEXT_${property} ${_MAGNUM_GLCONTEXT_ALIAS} ${property})\n            if(_MAGNUM_GLCONTEXT_${property})\n                set_target_properties(Magnum::GLContext PROPERTIES ${property}\n                    \"${_MAGNUM_GLCONTEXT_${property}}\")\n            endif()\n        endforeach()\n        get_target_property(_MAGNUM_GLCONTEXT_IMPORTED_LOCATION_RELEASE ${_MAGNUM_GLCONTEXT_ALIAS} IMPORTED_LOCATION_RELEASE)\n        get_target_property(_MAGNUM_GLCONTEXT_IMPORTED_LOCATION_DEBUG ${_MAGNUM_GLCONTEXT_ALIAS} IMPORTED_LOCATION_DEBUG)\n        if(_MAGNUM_GLCONTEXT_IMPORTED_LOCATION_RELEASE)\n            set_target_properties(Magnum::GLContext PROPERTIES\n                IMPORTED_LOCATION_RELEASE ${_MAGNUM_GLCONTEXT_IMPORTED_LOCATION_RELEASE})\n        endif()\n        if(_MAGNUM_GLCONTEXT_IMPORTED_LOCATION_DEBUG)\n            set_target_properties(Magnum::GLContext PROPERTIES\n                IMPORTED_LOCATION_DEBUG ${_MAGNUM_GLCONTEXT_IMPORTED_LOCATION_DEBUG})\n        endif()\n    endif()\n    # Prevent creating the alias again\n    unset(_MAGNUM_GLCONTEXT_ALIAS)\nendif()\n\n# Installation and deploy dirs\nset(MAGNUM_DEPLOY_PREFIX \".\"\n    CACHE STRING \"Prefix where to put final application executables\")\nset(MAGNUM_INCLUDE_INSTALL_PREFIX \".\"\n    CACHE STRING \"Prefix where to put platform-independent include and other files\")\n\ninclude(${CORRADE_LIB_SUFFIX_MODULE})\nset(MAGNUM_BINARY_INSTALL_DIR bin)\nset(MAGNUM_LIBRARY_INSTALL_DIR lib${LIB_SUFFIX})\nset(MAGNUM_DATA_INSTALL_DIR ${MAGNUM_INCLUDE_INSTALL_PREFIX}/share/magnum)\nset(MAGNUM_PLUGINS_DEBUG_BINARY_INSTALL_DIR ${MAGNUM_BINARY_INSTALL_DIR}/magnum-d)\nset(MAGNUM_PLUGINS_DEBUG_LIBRARY_INSTALL_DIR ${MAGNUM_LIBRARY_INSTALL_DIR}/magnum-d)\nset(MAGNUM_PLUGINS_RELEASE_BINARY_INSTALL_DIR ${MAGNUM_BINARY_INSTALL_DIR}/magnum)\nset(MAGNUM_PLUGINS_RELEASE_LIBRARY_INSTALL_DIR ${MAGNUM_LIBRARY_INSTALL_DIR}/magnum)\nset(MAGNUM_PLUGINS_FONT_DEBUG_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_BINARY_INSTALL_DIR}/fonts)\nset(MAGNUM_PLUGINS_FONT_DEBUG_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_LIBRARY_INSTALL_DIR}/fonts)\nset(MAGNUM_PLUGINS_FONT_RELEASE_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_BINARY_INSTALL_DIR}/fonts)\nset(MAGNUM_PLUGINS_FONT_RELEASE_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_LIBRARY_INSTALL_DIR}/fonts)\nset(MAGNUM_PLUGINS_FONTCONVERTER_DEBUG_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_BINARY_INSTALL_DIR}/fontconverters)\nset(MAGNUM_PLUGINS_FONTCONVERTER_RELEASE_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_LIBRARY_INSTALL_DIR}/fontconverters)\nset(MAGNUM_PLUGINS_IMAGECONVERTER_DEBUG_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_BINARY_INSTALL_DIR}/imageconverters)\nset(MAGNUM_PLUGINS_IMAGECONVERTER_DEBUG_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_LIBRARY_INSTALL_DIR}/imageconverters)\nset(MAGNUM_PLUGINS_IMAGECONVERTER_RELEASE_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_LIBRARY_INSTALL_DIR}/imageconverters)\nset(MAGNUM_PLUGINS_IMAGECONVERTER_RELEASE_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_BINARY_INSTALL_DIR}/imageconverters)\nset(MAGNUM_PLUGINS_IMPORTER_DEBUG_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_BINARY_INSTALL_DIR}/importers)\nset(MAGNUM_PLUGINS_IMPORTER_DEBUG_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_LIBRARY_INSTALL_DIR}/importers)\nset(MAGNUM_PLUGINS_IMPORTER_RELEASE_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_BINARY_INSTALL_DIR}/importers)\nset(MAGNUM_PLUGINS_IMPORTER_RELEASE_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_LIBRARY_INSTALL_DIR}/importers)\nset(MAGNUM_PLUGINS_AUDIOIMPORTER_DEBUG_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_BINARY_INSTALL_DIR}/audioimporters)\nset(MAGNUM_PLUGINS_AUDIOIMPORTER_DEBUG_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_LIBRARY_INSTALL_DIR}/audioimporters)\nset(MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_BINARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_BINARY_INSTALL_DIR}/audioimporters)\nset(MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_LIBRARY_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_LIBRARY_INSTALL_DIR}/audioimporters)\nset(MAGNUM_INCLUDE_INSTALL_DIR ${MAGNUM_INCLUDE_INSTALL_PREFIX}/include/Magnum)\nset(MAGNUM_EXTERNAL_INCLUDE_INSTALL_DIR ${MAGNUM_INCLUDE_INSTALL_PREFIX}/include/MagnumExternal)\nset(MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR ${MAGNUM_INCLUDE_INSTALL_PREFIX}/include/MagnumPlugins)\n\n# Get base plugin directory from main library location. This is *not* PATH,\n# because CMake always converts the path to an absolute location internally,\n# making it impossible to specify relative paths there. Sorry in advance for\n# not having the dir selection button in CMake GUI.\nset(MAGNUM_PLUGINS_DEBUG_DIR ${_MAGNUM_PLUGINS_DIR_PREFIX}/magnum-d\n    CACHE STRING \"Base directory where to look for Magnum plugins for debug builds\")\nset(MAGNUM_PLUGINS_RELEASE_DIR ${_MAGNUM_PLUGINS_DIR_PREFIX}/magnum\n    CACHE STRING \"Base directory where to look for Magnum plugins for release builds\")\nset(MAGNUM_PLUGINS_DIR ${_MAGNUM_PLUGINS_DIR_PREFIX}/magnum${_MAGNUM_PLUGINS_DIR_SUFFIX}\n    CACHE STRING \"Base directory where to look for Magnum plugins\")\n\n# Plugin directories\nset(MAGNUM_PLUGINS_FONT_DIR ${MAGNUM_PLUGINS_DIR}/fonts)\nset(MAGNUM_PLUGINS_FONT_DEBUG_DIR ${MAGNUM_PLUGINS_DEBUG_DIR}/fonts)\nset(MAGNUM_PLUGINS_FONT_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/fonts)\nset(MAGNUM_PLUGINS_FONTCONVERTER_DIR ${MAGNUM_PLUGINS_DIR}/fontconverters)\nset(MAGNUM_PLUGINS_FONTCONVERTER_DEBUG_DIR ${MAGNUM_PLUGINS_DEBUG_DIR}/fontconverters)\nset(MAGNUM_PLUGINS_FONTCONVERTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/fontconverters)\nset(MAGNUM_PLUGINS_IMAGECONVERTER_DIR ${MAGNUM_PLUGINS_DIR}/imageconverters)\nset(MAGNUM_PLUGINS_IMAGECONVERTER_DEBUG_DIR ${MAGNUM_PLUGINS_DEBUG_DIR}/imageconverters)\nset(MAGNUM_PLUGINS_IMAGECONVERTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/imageconverters)\nset(MAGNUM_PLUGINS_IMPORTER_DIR ${MAGNUM_PLUGINS_DIR}/importers)\nset(MAGNUM_PLUGINS_IMPORTER_DEBUG_DIR ${MAGNUM_PLUGINS_DEBUG_DIR}/importers)\nset(MAGNUM_PLUGINS_IMPORTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/importers)\nset(MAGNUM_PLUGINS_AUDIOIMPORTER_DIR ${MAGNUM_PLUGINS_DIR}/audioimporters)\nset(MAGNUM_PLUGINS_AUDIOIMPORTER_DEBUG_DIR ${MAGNUM_PLUGINS_DEBUG_DIR}/audioimporters)\nset(MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/audioimporters)\n"
  },
  {
    "path": "src/cmake/modules/FindMagnumIntegration.cmake",
    "content": "#.rst:\n# Find Magnum integration library\n# -------------------------------\n#\n# Finds the Magnum integration library. Basic usage::\n#\n#  find_package(MagnumIntegration REQUIRED)\n#\n# This command tries to find Magnum integration library and then defines the\n# following:\n#\n#  MagnumIntegration_FOUND      - Whether the library was found\n#\n# This command alone is useless without specifying the components:\n#\n#  Bullet                       - Bullet Physics integration library\n#  Dart                         - Dart Physics integration library\n#  Eigen                        - Eigen integration library\n#  Glm                          - GLM integration library\n#  ImGui                        - ImGui integration library\n#  Ovr                          - Oculus SDK integration library\n#\n# Example usage with specifying additional components is:\n#\n#  find_package(MagnumIntegration REQUIRED Bullet)\n#\n# For each component is then defined:\n#\n#  MagnumIntegration_*_FOUND    - Whether the component was found\n#  MagnumIntegration::*         - Component imported target\n#\n# The package is found if either debug or release version of each requested\n# library is found. If both debug and release libraries are found, proper\n# version is chosen based on actual build configuration of the project (i.e.\n# Debug build is linked to debug libraries, Release build to release\n# libraries).\n#\n# Additionally these variables are defined for internal usage:\n#\n#  MAGNUMINTEGRATION_INCLUDE_DIR - Magnum integration include dir (w/o\n#   dependencies)\n#  MAGNUMINTEGRATION_*_LIBRARY_DEBUG - Debug version of given library, if found\n#  MAGNUMINTEGRATION_*_LIBRARY_RELEASE - Release version of given library, if\n#   found\n#\n\n#\n#   This file is part of Magnum.\n#\n#   Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,\n#               2020 Vladimír Vondruš <mosra@centrum.cz>\n#   Copyright © 2018 Konstantinos Chatzilygeroudis <costashatz@gmail.com>\n#\n#   Permission is hereby granted, free of charge, to any person obtaining a\n#   copy of this software and associated documentation files (the \"Software\"),\n#   to deal in the Software without restriction, including without limitation\n#   the rights to use, copy, modify, merge, publish, distribute, sublicense,\n#   and/or sell copies of the Software, and to permit persons to whom the\n#   Software is furnished to do so, subject to the following conditions:\n#\n#   The above copyright notice and this permission notice shall be included\n#   in all copies or substantial portions of the Software.\n#\n#   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#   DEALINGS IN THE SOFTWARE.\n#\n\n# Magnum library dependencies\nset(_MAGNUMINTEGRATION_DEPENDENCIES )\nforeach(_component ${MagnumIntegration_FIND_COMPONENTS})\n    if(_component STREQUAL Bullet)\n        set(_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES SceneGraph Shaders GL)\n    elseif(_component STREQUAL Dart)\n        set(_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES SceneGraph Primitives MeshTools GL)\n    elseif(_component STREQUAL ImGui)\n        set(_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES GL Shaders)\n    endif()\n\n    list(APPEND _MAGNUMINTEGRATION_DEPENDENCIES ${_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES})\n    list(APPEND _MAGNUMINTEGRATION_OPTIONAL_DEPENDENCIES ${_MAGNUMINTEGRATION_${_component}_MAGNUM_OPTIONAL_DEPENDENCIES})\nendforeach()\nfind_package(Magnum REQUIRED ${_MAGNUMINTEGRATION_DEPENDENCIES})\nif(_MAGNUMINTEGRATION_OPTIONAL_DEPENDENCIES)\n    find_package(Magnum OPTIONAL_COMPONENTS ${_MAGNUMINTEGRATION_OPTIONAL_DEPENDENCIES})\nendif()\n\n# Global integration include dir\nfind_path(MAGNUMINTEGRATION_INCLUDE_DIR Magnum\n        HINTS ${MAGNUM_INCLUDE_DIR})\nmark_as_advanced(MAGNUMINTEGRATION_INCLUDE_DIR)\n\n# Component distinction (listing them explicitly to avoid mistakes with finding\n# components from other repositories)\nset(_MAGNUMINTEGRATION_LIBRARY_COMPONENT_LIST Bullet Dart Eigen ImGui Glm Ovr)\nset(_MAGNUMINTEGRATION_HEADER_ONLY_COMPONENT_LIST Eigen)\n\n# Inter-component dependencies (none yet)\n# set(_MAGNUMINTEGRATION_Component_DEPENDENCIES Dependency)\n\n# Ensure that all inter-component dependencies are specified as well\nset(_MAGNUMINTEGRATION_ADDITIONAL_COMPONENTS )\nforeach(_component ${MagnumIntegration_FIND_COMPONENTS})\n    # Mark the dependencies as required if the component is also required\n    if(MagnumIntegration_FIND_REQUIRED_${_component})\n        foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_DEPENDENCIES})\n            set(MagnumIntegration_FIND_REQUIRED_${_dependency} TRUE)\n        endforeach()\n    endif()\n\n    list(APPEND _MAGNUMINTEGRATION_ADDITIONAL_COMPONENTS ${_MAGNUMINTEGRATION_${_component}_DEPENDENCIES})\nendforeach()\n\n# Join the lists, remove duplicate components\nif(_MAGNUMINTEGRATION_ADDITIONAL_COMPONENTS)\n    list(INSERT MagnumIntegration_FIND_COMPONENTS 0 ${_MAGNUMINTEGRATION_ADDITIONAL_COMPONENTS})\nendif()\nif(MagnumIntegration_FIND_COMPONENTS)\n    list(REMOVE_DUPLICATES MagnumIntegration_FIND_COMPONENTS)\nendif()\n\n# Convert components lists to regular expressions so I can use if(MATCHES).\n# TODO: Drop this once CMake 3.3 and if(IN_LIST) can be used\nforeach(_WHAT LIBRARY HEADER_ONLY)\n    string(REPLACE \";\" \"|\" _MAGNUMINTEGRATION_${_WHAT}_COMPONENTS \"${_MAGNUMINTEGRATION_${_WHAT}_COMPONENT_LIST}\")\n    set(_MAGNUMINTEGRATION_${_WHAT}_COMPONENTS \"^(${_MAGNUMINTEGRATION_${_WHAT}_COMPONENTS})$\")\nendforeach()\n\n# Find all components\nforeach(_component ${MagnumIntegration_FIND_COMPONENTS})\n    string(TOUPPER ${_component} _COMPONENT)\n\n    # Create imported target in case the library is found. If the project is\n    # added as subproject to CMake, the target already exists and all the\n    # required setup is already done from the build tree.\n    if(TARGET MagnumIntegration::${_component})\n        set(MagnumIntegration_${_component}_FOUND TRUE)\n    else()\n        # Library components\n        if(_component MATCHES ${_MAGNUMINTEGRATION_LIBRARY_COMPONENTS} AND NOT _component MATCHES ${_MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS})\n            add_library(MagnumIntegration::${_component} UNKNOWN IMPORTED)\n\n            # Try to find both debug and release version\n            find_library(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_DEBUG Magnum${_component}Integration-d)\n            find_library(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_RELEASE Magnum${_component}Integration)\n            mark_as_advanced(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_DEBUG\n                    MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_RELEASE)\n\n            if(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_RELEASE)\n                set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                        IMPORTED_CONFIGURATIONS RELEASE)\n                set_property(TARGET MagnumIntegration::${_component} PROPERTY\n                        IMPORTED_LOCATION_RELEASE ${MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_RELEASE})\n            endif()\n\n            if(MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_DEBUG)\n                set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                        IMPORTED_CONFIGURATIONS DEBUG)\n                set_property(TARGET MagnumIntegration::${_component} PROPERTY\n                        IMPORTED_LOCATION_DEBUG ${MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_DEBUG})\n            endif()\n        endif()\n\n        # Header-only library components\n        if(_component MATCHES ${_MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS})\n            add_library(MagnumIntegration::${_component} INTERFACE IMPORTED)\n        endif()\n\n        # Bullet integration library\n        if(_component STREQUAL Bullet)\n            # On Emscripten, Bullet could be taken from ports. If that's the\n            # case, propagate proper compiler flag.\n            if(CORRADE_TARGET_EMSCRIPTEN)\n                find_file(_MAGNUMINTEGRATION_${_COMPONENT}_CONFIGURE_FILE configure.h\n                        HINTS ${MAGNUMINTEGRATION_INCLUDE_DIR}/Magnum/${_component}Integration)\n                file(READ ${_MAGNUMINTEGRATION_${_COMPONENT}_CONFIGURE_FILE} _magnum${_component}IntegrationConfigure)\n                string(FIND \"${_magnum${_component}IntegrationConfigure}\" \"#define MAGNUM_USE_EMSCRIPTEN_PORTS_BULLET\" _magnum${_component}Integration_USE_EMSCRIPTEN_PORTS_BULLET)\n                if(NOT _magnum${_component}Integration_USE_EMSCRIPTEN_PORTS_BULLET EQUAL -1)\n                    set(MAGNUM_USE_EMSCRIPTEN_PORTS_BULLET 1)\n                endif()\n            endif()\n\n            if(MAGNUM_USE_EMSCRIPTEN_PORTS_BULLET)\n                if(CMAKE_VERSION VERSION_LESS 3.13)\n                    message(FATAL_ERROR \"BulletIntegration was compiled against emscripten-ports version but linking to it requires CMake 3.13 at least\")\n                endif()\n                set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                        INTERFACE_COMPILE_OPTIONS \"SHELL:-s USE_BULLET=1\")\n                set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_OPTIONS \"SHELL:-s USE_BULLET=1\")\n            else()\n                find_package(Bullet)\n\n                set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                        INTERFACE_INCLUDE_DIRECTORIES ${BULLET_INCLUDE_DIRS})\n                # Need to handle special cases where both debug and release\n                # libraries are available (in form of debug;A;optimized;B in\n                # BULLET_LIBRARIES), thus appending them one by one\n                foreach(lib BULLET_DYNAMICS_LIBRARY BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY BULLET_SOFTBODY_LIBRARY)\n                    if(${lib}_DEBUG)\n                        set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                                INTERFACE_LINK_LIBRARIES \"$<$<NOT:$<CONFIG:Debug>>:${${lib}}>;$<$<CONFIG:Debug>:${${lib}_DEBUG}>\")\n                    else()\n                        set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                                INTERFACE_LINK_LIBRARIES ${${lib}})\n                    endif()\n                endforeach()\n            endif()\n\n            set(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES MotionState.h)\n\n            # Eigen integration library\n        elseif(_component STREQUAL Eigen)\n            find_package(Eigen3)\n            # We could drop this once we can use at least 3.3.1 (Ubuntu 16.04\n            # has only 3.3 beta, which doesn't have this target yet), however\n            # for Travis and AppVeyor we're using FindEigen3.cmake from the\n            # downloaded sources (because the Eigen3Config.cmake, which\n            # produces the actual targets, is not there -- only\n            # Eigen3Config.cmake.in). See the YML files for an extended rant.\n            # Also, FindEigen3 only defines EIGEN3_INCLUDE_DIR, not even\n            # EIGEN3_INCLUDE_DIRS, so be extra careful.\n            # http://eigen.tuxfamily.org/index.php?title=ChangeLog#Eigen_3.3.1\n            set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                    INTERFACE_INCLUDE_DIRECTORIES ${EIGEN3_INCLUDE_DIR})\n\n            set(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES Integration.h)\n\n            # ImGui integration library\n        elseif(_component STREQUAL ImGui)\n            find_package(ImGui)\n            set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES ImGui::ImGui)\n\n            set(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES Integration.h)\n\n            # GLM integration library\n        elseif(_component STREQUAL Glm)\n            find_package(GLM)\n            set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES GLM::GLM)\n\n            set(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES Integration.h)\n\n            # Dart integration library\n        elseif(_component STREQUAL Dart)\n            find_package(DART 6.0.0 CONFIG REQUIRED)\n            set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES dart)\n\n            set(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES ConvertShapeNode.h)\n\n            # Oculus SDK integration library\n        elseif(_component STREQUAL Ovr)\n            find_package(OVR)\n            set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES OVR::OVR)\n\n            set(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES OvrIntegration.h)\n        endif()\n\n        # Find library includes\n        if(_component MATCHES ${_MAGNUMINTEGRATION_LIBRARY_COMPONENTS})\n            find_path(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_DIR\n                    NAMES ${_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_PATH_NAMES}\n                    HINTS ${MAGNUMINTEGRATION_INCLUDE_DIR}/Magnum/${_component}Integration)\n            mark_as_advanced(_MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_DIR)\n        endif()\n\n        if(_component MATCHES ${_MAGNUMINTEGRATION_LIBRARY_COMPONENTS})\n            # Link to core Magnum library, add other Magnum required and\n            # optional dependencies\n            set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                    INTERFACE_LINK_LIBRARIES Magnum::Magnum)\n            foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_MAGNUM_DEPENDENCIES})\n                set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES Magnum::${_dependency})\n            endforeach()\n            foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_MAGNUM_OPTIONAL_DEPENDENCIES})\n                if(Magnum_${_dependency}_FOUND)\n                    set_property(TARGET MagnumIntegration::${_component} APPEND     PROPERTY\n                            INTERFACE_LINK_LIBRARIES Magnum::${_dependency})\n                endif()\n            endforeach()\n\n            # Add inter-project dependencies\n            foreach(_dependency ${_MAGNUMINTEGRATION_${_component}_DEPENDENCIES})\n                set_property(TARGET MagnumIntegration::${_component} APPEND PROPERTY\n                        INTERFACE_LINK_LIBRARIES MagnumIntegration::${_dependency})\n            endforeach()\n        endif()\n\n        # Decide if the library was found\n        if(_component MATCHES ${_MAGNUMINTEGRATION_LIBRARY_COMPONENTS} AND _MAGNUMINTEGRATION_${_COMPONENT}_INCLUDE_DIR AND (_component MATCHES ${_MAGNUMINTEGRATION_HEADER_ONLY_COMPONENTS} OR MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_DEBUG OR MAGNUMINTEGRATION_${_COMPONENT}_LIBRARY_RELEASE))\n            set(MagnumIntegration_${_component}_FOUND TRUE)\n        else()\n            set(MagnumIntegration_${_component}_FOUND FALSE)\n        endif()\n    endif()\nendforeach()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(MagnumIntegration\n        REQUIRED_VARS MAGNUMINTEGRATION_INCLUDE_DIR\n        HANDLE_COMPONENTS)\n"
  },
  {
    "path": "src/cmake/modules/FindSDL2.cmake",
    "content": "#.rst:\n# Find SDL2\n# ---------\n#\n# Finds the SDL2 library. This module defines:\n#\n#  SDL2_FOUND               - True if SDL2 library is found\n#  SDL2::SDL2               - SDL2 imported target\n#\n# Additionally these variables are defined for internal usage:\n#\n#  SDL2_LIBRARY_DEBUG       - SDL2 debug library, if found\n#  SDL2_LIBRARY_RELEASE     - SDL2 release library, if found\n#  SDL2_DLL_DEBUG           - SDL2 debug DLL on Windows, if found\n#  SDL2_DLL_RELEASE         - SDL2 release DLL on Windows, if found\n#  SDL2_INCLUDE_DIR         - Root include dir\n#\n\n#\n#   This file is part of Magnum.\n#\n#   Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019\n#             Vladimír Vondruš <mosra@centrum.cz>\n#   Copyright © 2018 Jonathan Hale <squareys@googlemail.com>\n#\n#   Permission is hereby granted, free of charge, to any person obtaining a\n#   copy of this software and associated documentation files (the \"Software\"),\n#   to deal in the Software without restriction, including without limitation\n#   the rights to use, copy, modify, merge, publish, distribute, sublicense,\n#   and/or sell copies of the Software, and to permit persons to whom the\n#   Software is furnished to do so, subject to the following conditions:\n#\n#   The above copyright notice and this permission notice shall be included\n#   in all copies or substantial portions of the Software.\n#\n#   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#   DEALINGS IN THE SOFTWARE.\n#\n\n# In Emscripten SDL is linked automatically, thus no need to find the library.\n# Also the includes are in SDL subdirectory, not SDL2.\nif(CORRADE_TARGET_EMSCRIPTEN)\n    set(_SDL2_PATH_SUFFIXES SDL)\nelse()\n    set(_SDL2_PATH_SUFFIXES SDL2)\n    if(WIN32)\n        # Precompiled libraries for MSVC are in x86/x64 subdirectories\n        if(MSVC)\n            if(CMAKE_SIZEOF_VOID_P EQUAL 8)\n                set(_SDL2_LIBRARY_PATH_SUFFIX lib/x64)\n            elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)\n                set(_SDL2_LIBRARY_PATH_SUFFIX lib/x86)\n            endif()\n\n        # Both includes and libraries for MinGW are in some directory deep\n        # inside. There's also a CMake config file but it has HARDCODED path\n        # to /opt/local/i686-w64-mingw32, which doesn't make ANY SENSE,\n        # especially on Windows.\n        elseif(MINGW)\n            if(CMAKE_SIZEOF_VOID_P EQUAL 8)\n                set(_SDL2_LIBRARY_PATH_SUFFIX x86_64-w64-mingw32/lib)\n                set(_SDL2_RUNTIME_PATH_SUFFIX x86_64-w64-mingw32/bin)\n                list(APPEND _SDL2_PATH_SUFFIXES x86_64-w64-mingw32/include/SDL2)\n            elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)\n                set(_SDL2_LIBRARY_PATH_SUFFIX i686-w64-mingw32/lib)\n                set(_SDL2_RUNTIME_PATH_SUFFIX i686-w64-mingw32/lib)\n                list(APPEND _SDL2_PATH_SUFFIXES i686-w64-mingw32/include/SDL2)\n            endif()\n        else()\n            message(FATAL_ERROR \"Unsupported compiler\")\n        endif()\n    endif()\n\n    find_library(SDL2_LIBRARY_RELEASE\n        # Compiling SDL2 from scratch on macOS creates dead libSDL2.so symlink\n        # which CMake somehow prefers before the SDL2-2.0.dylib file. Making\n        # the dylib first so it is preferred. Not sure how this maps to debug\n        # config though :/\n        NAMES SDL2-2.0 SDL2\n        PATH_SUFFIXES ${_SDL2_LIBRARY_PATH_SUFFIX})\n    find_library(SDL2_LIBRARY_DEBUG\n        NAMES SDL2d\n        PATH_SUFFIXES ${_SDL2_LIBRARY_PATH_SUFFIX})\n    # FPHSA needs one of the _DEBUG/_RELEASE variables to check that the\n    # library was found -- using SDL_LIBRARY, which will get populated by\n    # select_library_configurations() below.\n    set(SDL2_LIBRARY_NEEDED SDL2_LIBRARY)\nendif()\n\ninclude(SelectLibraryConfigurations)\nselect_library_configurations(SDL2)\n\n# Include dir\nfind_path(SDL2_INCLUDE_DIR\n    # We must search file which is present only in SDL2 and not in SDL1.\n    # Apparently when both SDL.h and SDL_scancode.h are specified, CMake is\n    # happy enough that it found SDL.h and doesn't bother about the other.\n    #\n    # On macOS, where the includes are not in SDL2/SDL.h form (which would\n    # solve this issue), but rather SDL2.framework/Headers/SDL.h, CMake might\n    # find SDL.framework/Headers/SDL.h if SDL1 is installed, which is wrong.\n    NAMES SDL_scancode.h\n    PATH_SUFFIXES ${_SDL2_PATH_SUFFIXES})\n\n# DLL on Windows\nif(CORRADE_TARGET_WINDOWS)\n    find_file(SDL2_DLL_RELEASE\n        NAMES SDL2.dll\n        PATH_SUFFIXES ${_SDL2_RUNTIME_PATH_SUFFIX} ${_SDL2_LIBRARY_PATH_SUFFIX})\n    find_file(SDL2_DLL_DEBUG\n        NAMES SDL2d.dll # not sure?\n        PATH_SUFFIXES ${_SDL2_RUNTIME_PATH_SUFFIX} ${_SDL2_LIBRARY_PATH_SUFFIX})\nendif()\n\n# iOS dependencies\nif(CORRADE_TARGET_IOS)\n    set(_SDL2_FRAMEWORKS\n        AudioToolbox\n        AVFoundation\n        CoreGraphics\n        CoreMotion\n        Foundation\n        GameController\n        QuartzCore\n        UIKit)\n    set(_SDL2_FRAMEWORK_LIBRARIES )\n    foreach(framework ${_SDL2_FRAMEWORKS})\n        find_library(_SDL2_${framework}_LIBRARY ${framework})\n        mark_as_advanced(_SDL2_${framework}_LIBRARY)\n        list(APPEND _SDL2_FRAMEWORK_LIBRARIES ${_SDL2_${framework}_LIBRARY})\n        list(APPEND _SDL2_FRAMEWORK_LIBRARY_NAMES _SDL2_${framework}_LIBRARY)\n    endforeach()\nendif()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(\"SDL2\" DEFAULT_MSG\n    ${SDL2_LIBRARY_NEEDED}\n    ${_SDL2_FRAMEWORK_LIBRARY_NAMES}\n    SDL2_INCLUDE_DIR)\n\nif(NOT TARGET SDL2::SDL2)\n    if(SDL2_LIBRARY_NEEDED)\n        add_library(SDL2::SDL2 UNKNOWN IMPORTED)\n\n        # Work around BUGGY framework support on macOS\n        # https://cmake.org/Bug/view.php?id=14105\n        if(CORRADE_TARGET_APPLE AND SDL2_LIBRARY_RELEASE MATCHES \"\\\\.framework$\")\n            set_property(TARGET SDL2::SDL2 APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)\n            set_property(TARGET SDL2::SDL2 PROPERTY IMPORTED_LOCATION_RELEASE ${SDL2_LIBRARY_RELEASE}/SDL2)\n        else()\n            if(SDL2_LIBRARY_RELEASE)\n                set_property(TARGET SDL2::SDL2 APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)\n                set_property(TARGET SDL2::SDL2 PROPERTY IMPORTED_LOCATION_RELEASE ${SDL2_LIBRARY_RELEASE})\n            endif()\n\n            if(SDL2_LIBRARY_DEBUG)\n                set_property(TARGET SDL2::SDL2 APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)\n                set_property(TARGET SDL2::SDL2 PROPERTY IMPORTED_LOCATION_DEBUG ${SDL2_LIBRARY_DEBUG})\n            endif()\n        endif()\n\n        # Link additional `dl` and `pthread` libraries required by a static\n        # build of SDL on Unixy platforms (except Apple, where it is most\n        # probably some frameworks instead)\n        if(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE AND SDL2_LIBRARY MATCHES \"${CMAKE_STATIC_LIBRARY_SUFFIX}$\")\n            find_package(Threads)\n            set_property(TARGET SDL2::SDL2 APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})\n        endif()\n\n        # Link frameworks on iOS\n        if(CORRADE_TARGET_IOS)\n            set_property(TARGET SDL2::SDL2 APPEND PROPERTY\n                INTERFACE_LINK_LIBRARIES ${_SDL2_FRAMEWORK_LIBRARIES})\n        endif()\n    else()\n        add_library(SDL2::SDL2 INTERFACE IMPORTED)\n    endif()\n\n    set_property(TARGET SDL2::SDL2 PROPERTY\n        INTERFACE_INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR})\nendif()\n\nmark_as_advanced(SDL2_INCLUDE_DIR)\n"
  },
  {
    "path": "src/cmake/util.cmake",
    "content": "set(CURRENT_DIR \"${CMAKE_CURRENT_LIST_DIR}\")\n\nmacro(set_compiler_flags)\n  if(MSVC)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /Za\")\n    message(STATUS \"Disable Microsoft language extensions: ${CMAKE_CXX_FLAGS}\")\n  endif()\n\n  if(MSVC)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /MP\")\n    message(STATUS \"Added parallel build arguments to CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}\")\n  endif()\n\n  if(MSVC)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /Ot\")\n    message(STATUS \"Added optimization flags CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}\")\n  endif()\n\n  if(MSVC)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /W4\")\n  else()\n    add_compile_options(-Wall -Wextra -Wdelete-non-virtual-dtor)\n  endif()\n\n  add_definitions(-D_SCL_SECURE_NO_WARNINGS)  # VS annoying warnings\n  add_definitions(-D_CRT_SECURE_NO_WARNINGS)  # VS annoying warnings\n  add_definitions(-D_USE_MATH_DEFINES)  # to enable stuff like M_PI\nendmacro()\n\nmacro(find_modules)\n  find_package(OpenCV REQUIRED)\n  include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS})\nendmacro()\n\nmacro(common_settings)\n  set_property(GLOBAL PROPERTY USE_FOLDERS ON)\n\n  set_compiler_flags()\n\n  find_modules()\nendmacro()\n\nmacro(collect_sources_default name)\n  file(GLOB SOURCES src/*.c src/*.cpp)\n  file(GLOB HEADERS include/${name}/*.h include/${name}/*.hpp)\n  message(STATUS \"${name} sources ${SOURCES}\")\n  message(STATUS \"${name} headers ${HEADERS}\")\nendmacro()\n\nmacro(set_default_properties target folder_name)\n  set_target_properties(${target} PROPERTIES FOLDER ${folder_name})\nendmacro()\n\nmacro(add_library_default name)\n  collect_sources_default(${name})\n  add_library(${name} STATIC ${SOURCES} ${HEADERS})\n  include_directories(include)\n  set_default_properties(${name} \"libs\")\n  target_include_directories(${name} PUBLIC include)\nendmacro()\n\nmacro(add_app_default name src)\n  message(STATUS \"APP ${name} sources ${src}\")\n  add_executable(${name} ${src})\n  set_default_properties(${name} \"apps\")\nendmacro()\n\nmacro(add_test_default name)\n  collect_sources_default(${name})\n  add_executable(${name} ${SOURCES} ${HEADERS})\n  set_default_properties(${name} \"tests\")\nendmacro()\n"
  },
  {
    "path": "src/examples/CMakeLists.txt",
    "content": "if (BUILD_GUI_APPS)\n    add_subdirectory(textured_triangle)\n    add_subdirectory(picking_objects)\n    add_subdirectory(arcball)\n    add_subdirectory(bullet_example)\nendif()\n"
  },
  {
    "path": "src/examples/arcball/ArcBall.cpp",
    "content": "/*\n    This file is part of Magnum.\n\n    Original authors — credit is appreciated but not required:\n\n        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 —\n            Vladimír Vondruš <mosra@centrum.cz>\n        2020 — Nghia Truong <nghiatruong.vn@gmail.com>\n\n    This is free and unencumbered software released into the public domain.\n\n    Anyone is free to copy, modify, publish, use, compile, sell, or distribute\n    this software, either in source code form or as a compiled binary, for any\n    purpose, commercial or non-commercial, and by any means.\n\n    In jurisdictions that recognize copyright laws, the author or authors of\n    this software dedicate any and all copyright interest in the software to\n    the public domain. We make this dedication for the benefit of the public\n    at large and to the detriment of our heirs and successors. We intend this\n    dedication to be an overt act of relinquishment in perpetuity of all\n    present and future rights to this software under copyright law.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n    THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#include \"ArcBall.h\"\n\n#include <Magnum/Math/Matrix3.h>\n\nnamespace Magnum { namespace Examples {\n\nnamespace {\n\n/* Project a point in NDC onto the arcball sphere */\nQuaternion ndcToArcBall(const Vector2& p) {\n    const Float dist = Math::dot(p, p);\n\n    /* Point is on sphere */\n    if(dist <= 1.0f)\n        return {{p.x(), p.y(), Math::sqrt(1.0f - dist)}, 0.0f};\n\n    /* Point is outside sphere */\n    else {\n        const Vector2 proj = p.normalized();\n        return {{proj.x(), proj.y(), 0.0f}, 0.0f};\n    }\n}\n\n}\n\nArcBall::ArcBall(const Vector3& eye, const Vector3& viewCenter,\n    const Vector3& upDir, Deg fov, const Vector2i& windowSize):\n    _fov{fov}, _windowSize{windowSize}\n{\n    setViewParameters(eye, viewCenter, upDir);\n}\n\nvoid ArcBall::setViewParameters(const Vector3& eye, const Vector3& viewCenter,\n    const Vector3& upDir)\n{\n    const Vector3 dir = viewCenter - eye;\n    Vector3 zAxis = dir.normalized();\n    Vector3 xAxis = (Math::cross(zAxis, upDir.normalized())).normalized();\n    Vector3 yAxis = (Math::cross(xAxis, zAxis)).normalized();\n    xAxis = (Math::cross(zAxis, yAxis)).normalized();\n\n    _targetPosition = -viewCenter;\n    _targetZooming = -dir.length();\n    _targetQRotation = Quaternion::fromMatrix(\n        Matrix3x3{xAxis, yAxis, -zAxis}.transposed()).normalized();\n\n    _positionT0  = _currentPosition = _targetPosition;\n    _zoomingT0 = _currentZooming = _targetZooming;\n    _qRotationT0 = _currentQRotation = _targetQRotation;\n\n    updateInternalTransformations();\n}\n\nvoid ArcBall::reset() {\n    _targetPosition = _positionT0;\n    _targetZooming = _zoomingT0;\n    _targetQRotation = _qRotationT0;\n}\n\nvoid ArcBall::setLagging(const Float lagging) {\n    CORRADE_INTERNAL_ASSERT(lagging >= 0.0f && lagging < 1.0f);\n    _lagging = lagging;\n}\n\nvoid ArcBall::initTransformation(const Vector2i& mousePos) {\n    _prevMousePosNDC = screenCoordToNDC(mousePos);\n}\n\nvoid ArcBall::rotate(const Vector2i& mousePos) {\n    const Vector2 mousePosNDC = screenCoordToNDC(mousePos);\n    const Quaternion currentQRotation = ndcToArcBall(mousePosNDC);\n    const Quaternion prevQRotation = ndcToArcBall(_prevMousePosNDC);\n    _prevMousePosNDC = mousePosNDC;\n    _targetQRotation =\n        (currentQRotation*prevQRotation*_targetQRotation).normalized();\n}\n\nvoid ArcBall::translate(const Vector2i& mousePos) {\n    const Vector2 mousePosNDC = screenCoordToNDC(mousePos);\n    const Vector2 translationNDC = mousePosNDC - _prevMousePosNDC;\n    _prevMousePosNDC = mousePosNDC;\n    translateDelta(translationNDC);\n}\n\nvoid ArcBall::translateDelta(const Vector2& translationNDC) {\n    /* Half size of the screen viewport at the view center and perpendicular\n       with the viewDir */\n    const Float hh = Math::abs(_targetZooming)*Math::tan(_fov*0.5f);\n    const Float hw = hh*Vector2{_windowSize}.aspectRatio();\n\n    _targetPosition += _inverseView.transformVector(\n        {translationNDC.x()*hw, translationNDC.y()*hh, 0.0f});\n}\n\nvoid ArcBall::zoom(const Float delta) {\n    _targetZooming += delta;\n}\n\nbool ArcBall::updateTransformation() {\n    const Vector3 diffViewCenter = _targetPosition - _currentPosition;\n    const Quaternion diffRotation = _targetQRotation - _currentQRotation;\n    const Float diffZooming = _targetZooming - _currentZooming;\n\n    const Float dViewCenter = Math::dot(diffViewCenter, diffViewCenter);\n    const Float dRotation = Math::dot(diffRotation, diffRotation);\n    const Float dZooming = diffZooming * diffZooming;\n\n    /* Nothing change */\n    if(dViewCenter < 1.0e-10f &&\n       dRotation < 1.0e-10f &&\n       dZooming < 1.0e-10f) {\n        return false;\n    }\n\n    /* Nearly done: just jump directly to the target */\n    if(dViewCenter < 1.0e-6f &&\n       dRotation < 1.0e-6f &&\n       dZooming < 1.0e-6f) {\n        _currentPosition  = _targetPosition;\n        _currentQRotation = _targetQRotation;\n        _currentZooming   = _targetZooming;\n\n    /* Interpolate between the current transformation and the target\n       transformation */\n    } else {\n        const Float t = 1 - _lagging;\n        _currentPosition = Math::lerp(_currentPosition, _targetPosition, t);\n        _currentZooming  = Math::lerp(_currentZooming, _targetZooming, t);\n        _currentQRotation = Math::slerpShortestPath(\n            _currentQRotation, _targetQRotation, t);\n    }\n\n    updateInternalTransformations();\n    return true;\n}\n\nvoid ArcBall::updateInternalTransformations() {\n    _view = DualQuaternion::translation(Vector3::zAxis(_currentZooming))*\n            DualQuaternion{_currentQRotation}*\n            DualQuaternion::translation(_currentPosition);\n    _inverseView = _view.inverted();\n}\n\nVector2 ArcBall::screenCoordToNDC(const Vector2i& mousePos) const {\n    return {mousePos.x()*2.0f/_windowSize.x() - 1.0f,\n            1.0f - 2.0f*mousePos.y()/ _windowSize.y()};\n}\n\n}}\n"
  },
  {
    "path": "src/examples/arcball/ArcBall.h",
    "content": "#ifndef Magnum_Examples_ArcBall_h\n#define Magnum_Examples_ArcBall_h\n/*\n    This file is part of Magnum.\n\n    Original authors — credit is appreciated but not required:\n\n        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 —\n            Vladimír Vondruš <mosra@centrum.cz>\n        2020 — Nghia Truong <nghiatruong.vn@gmail.com>\n\n    This is free and unencumbered software released into the public domain.\n\n    Anyone is free to copy, modify, publish, use, compile, sell, or distribute\n    this software, either in source code form or as a compiled binary, for any\n    purpose, commercial or non-commercial, and by any means.\n\n    In jurisdictions that recognize copyright laws, the author or authors of\n    this software dedicate any and all copyright interest in the software to\n    the public domain. We make this dedication for the benefit of the public\n    at large and to the detriment of our heirs and successors. We intend this\n    dedication to be an overt act of relinquishment in perpetuity of all\n    present and future rights to this software under copyright law.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n    THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <Magnum/Magnum.h>\n#include <Magnum/Math/Functions.h>\n#include <Magnum/Math/DualQuaternion.h>\n#include <Magnum/Math/Vector2.h>\n#include <Magnum/Math/Vector3.h>\n\nnamespace Magnum { namespace Examples {\n\n/* Implementation of Ken Shoemake's arcball camera with smooth navigation\n   feature: https://www.talisman.org/~erlkonig/misc/shoemake92-arcball.pdf */\nclass ArcBall {\n    public:\n        ArcBall(const Vector3& cameraPosition, const Vector3& viewCenter,\n            const Vector3& upDir, Deg fov, const Vector2i& windowSize);\n\n        /* Set the camera view parameters: eye position, view center, up\n           direction */\n        void setViewParameters(const Vector3& eye, const Vector3& viewCenter,\n            const Vector3& upDir);\n\n        /* Reset the camera to its initial position, view center, and up dir */\n        void reset();\n\n        /* Update screen size after the window has been resized */\n        void reshape(const Vector2i& windowSize) { _windowSize = windowSize; }\n\n        /* Update any unfinished transformation due to lagging, return true if\n           the camera matrices have changed */\n        bool updateTransformation();\n\n        /* Get/set the amount of lagging such that the camera will (slowly)\n           smoothly navigate. Lagging must be in [0, 1) */\n        Float lagging() const { return _lagging; }\n        void setLagging(Float lagging);\n\n        /* Initialize the first (screen) mouse position for camera\n           transformation. This should be called in mouse pressed event. */\n        void initTransformation(const Vector2i& mousePos);\n\n        /* Rotate the camera from the previous (screen) mouse position to the\n           current (screen) position */\n        void rotate(const Vector2i& mousePos);\n\n        /* Translate the camera from the previous (screen) mouse position to\n           the current (screen) mouse position */\n        void translate(const Vector2i& mousePos);\n\n        /* Translate the camera by the delta amount of (NDC) mouse position.\n           Note that NDC position must be in [-1, -1] to [1, 1]. */\n        void translateDelta(const Vector2& translationNDC);\n\n        /* Zoom the camera (positive delta = zoom in, negative = zoom out) */\n        void zoom(Float delta);\n\n        /* Field of view */\n        Deg fov() const { return _fov; }\n\n        /* Get the camera's view transformation as a qual quaternion */\n        const DualQuaternion& view() const { return _view; }\n\n        /* Get the camera's view transformation as a matrix */\n        Matrix4 viewMatrix() const { return _view.toMatrix(); }\n\n        /* Get the camera's inverse view matrix (which also produces\n           transformation of the camera) */\n        Matrix4 inverseViewMatrix() const { return _inverseView.toMatrix(); }\n\n        /* Get the camera's transformation as a dual quaternion */\n        const DualQuaternion& transformation() const { return _inverseView; }\n\n        /* Get the camera's transformation matrix */\n        Matrix4 transformationMatrix() const { return _inverseView.toMatrix(); }\n\n        /* Return the distance from the camera position to the center view */\n        Float viewDistance() const { return Math::abs(_targetZooming); }\n\n    protected:\n        /* Update the camera transformations */\n        void updateInternalTransformations();\n\n        /* Transform from screen coordinate to NDC - normalized device\n           coordinate. The top-left of the screen corresponds to [-1, 1] NDC,\n           and the bottom right is [1, -1] NDC. */\n        Vector2 screenCoordToNDC(const Vector2i& mousePos) const;\n\n        Deg _fov;\n        Vector2i _windowSize;\n\n        Vector2 _prevMousePosNDC;\n        Float _lagging{};\n\n        Vector3 _targetPosition, _currentPosition, _positionT0;\n        Quaternion _targetQRotation, _currentQRotation, _qRotationT0;\n        Float _targetZooming, _currentZooming, _zoomingT0;\n        DualQuaternion _view, _inverseView;\n};\n\n}}\n\n#endif\n"
  },
  {
    "path": "src/examples/arcball/ArcBallCamera.h",
    "content": "#ifndef Magnum_Examples_ArcBallCamera_h\n#define Magnum_Examples_ArcBallCamera_h\n/*\n    This file is part of Magnum.\n\n    Original authors — credit is appreciated but not required:\n\n        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 —\n            Vladimír Vondruš <mosra@centrum.cz>\n        2020 — Nghia Truong <nghiatruong.vn@gmail.com>\n\n    This is free and unencumbered software released into the public domain.\n\n    Anyone is free to copy, modify, publish, use, compile, sell, or distribute\n    this software, either in source code form or as a compiled binary, for any\n    purpose, commercial or non-commercial, and by any means.\n\n    In jurisdictions that recognize copyright laws, the author or authors of\n    this software dedicate any and all copyright interest in the software to\n    the public domain. We make this dedication for the benefit of the public\n    at large and to the detriment of our heirs and successors. We intend this\n    dedication to be an overt act of relinquishment in perpetuity of all\n    present and future rights to this software under copyright law.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n    THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <Magnum/SceneGraph/Camera.h>\n#include <Magnum/SceneGraph/AbstractTranslationRotation3D.h>\n#include <Magnum/SceneGraph/Object.h>\n#include <Magnum/SceneGraph/Scene.h>\n\n#include \"ArcBall.h\"\n\nnamespace Magnum { namespace Examples {\n\n/* Arcball camera implementation integrated into the SceneGraph */\nclass ArcBallCamera: public ArcBall {\n    public:\n        template<class Transformation> ArcBallCamera(\n            SceneGraph::Scene<Transformation>& scene,\n            const Vector3& cameraPosition, const Vector3& viewCenter,\n            const Vector3& upDir, Deg fov, const Vector2i& windowSize,\n            const Vector2i& viewportSize):\n            ArcBall{cameraPosition, viewCenter, upDir, fov, windowSize}\n        {\n            /* Create a camera object of a concrete type */\n            auto* cameraObject = new SceneGraph::Object<Transformation>{&scene};\n            (*(_camera = new SceneGraph::Camera3D{*cameraObject}))\n                .setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)\n                .setProjectionMatrix(Matrix4::perspectiveProjection(\n                    fov, Vector2{windowSize}.aspectRatio(), 0.01f, 100.0f))\n                .setViewport(viewportSize);\n\n            /* Save the abstract transformation interface and initialize the\n               camera position through that */\n            (*(_cameraObject = cameraObject))\n                .rotate(transformation().rotation())\n                .translate(transformation().translation());\n        }\n\n        /* Update screen and viewport size after the window has been resized */\n        void reshape(const Vector2i& windowSize, const Vector2i& viewportSize) {\n            _windowSize = windowSize;\n            _camera->setViewport(viewportSize);\n        }\n\n        /* Update the SceneGraph camera if arcball has been changed */\n        bool update() {\n            /* call the internal update */\n            if(!updateTransformation()) return false;\n\n            (*_cameraObject)\n                .resetTransformation()\n                .rotate(transformation().rotation())\n                .translate(transformation().translation());\n            return true;\n        }\n\n        /* Draw objects using the internal scenegraph camera */\n        void draw(SceneGraph::DrawableGroup3D& drawables) {\n            _camera->draw(drawables);\n        }\n\n        /* Accessor to the raw camera object */\n        SceneGraph::Camera3D& camera() const { return *_camera; }\n\n    private:\n        SceneGraph::AbstractTranslationRotation3D* _cameraObject{};\n        SceneGraph::Camera3D* _camera{};\n};\n\n}}\n\n#endif\n"
  },
  {
    "path": "src/examples/arcball/ArcBallExample.cpp",
    "content": "/*\n    This file is part of Magnum.\n\n    Original authors — credit is appreciated but not required:\n\n        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 —\n            Vladimír Vondruš <mosra@centrum.cz>\n        2020 — Nghia Truong <nghiatruong.vn@gmail.com>\n\n    This is free and unencumbered software released into the public domain.\n\n    Anyone is free to copy, modify, publish, use, compile, sell, or distribute\n    this software, either in source code form or as a compiled binary, for any\n    purpose, commercial or non-commercial, and by any means.\n\n    In jurisdictions that recognize copyright laws, the author or authors of\n    this software dedicate any and all copyright interest in the software to\n    the public domain. We make this dedication for the benefit of the public\n    at large and to the detriment of our heirs and successors. We intend this\n    dedication to be an overt act of relinquishment in perpetuity of all\n    present and future rights to this software under copyright law.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n    THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#include <Corrade/Containers/Optional.h>\n#include <Magnum/DebugTools/ColorMap.h>\n#include <Magnum/ImageView.h>\n#include <Magnum/PixelFormat.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n#include <Magnum/GL/Mesh.h>\n#include <Magnum/GL/Renderer.h>\n#include <Magnum/GL/Texture.h>\n#include <Magnum/GL/TextureFormat.h>\n#include <Magnum/Math/Color.h>\n#include <Magnum/Math/Matrix4.h>\n#include <Magnum/MeshTools/Compile.h>\n#include <Magnum/Platform/Sdl2Application.h>\n#include <Magnum/Primitives/Cube.h>\n#include <Magnum/SceneGraph/Camera.h>\n#include <Magnum/SceneGraph/Drawable.h>\n#include <Magnum/SceneGraph/MatrixTransformation3D.h>\n#include <Magnum/SceneGraph/Object.h>\n#include <Magnum/SceneGraph/Scene.h>\n#include <Magnum/Shaders/MeshVisualizer.h>\n#include <Magnum/Trade/MeshData.h>\n\n#include \"ArcBall.h\"\n#include \"ArcBallCamera.h\"\n\nnamespace Magnum { namespace Examples {\n\nusing Object3D = SceneGraph::Object<SceneGraph::MatrixTransformation3D>;\nusing Scene3D = SceneGraph::Scene<SceneGraph::MatrixTransformation3D>;\n\nusing namespace Math::Literals;\n\nclass ArcBallExample: public Platform::Application {\n    public:\n        explicit ArcBallExample(const Arguments& arguments);\n\n    private:\n        void drawEvent() override;\n        void viewportEvent(ViewportEvent& event) override;\n        void keyPressEvent(KeyEvent& event) override;\n        void mousePressEvent(MouseEvent& event) override;\n        void mouseReleaseEvent(MouseEvent& event) override;\n        void mouseMoveEvent(MouseMoveEvent& event) override;\n        void mouseScrollEvent(MouseScrollEvent& event) override;\n\n        Scene3D _scene;\n        SceneGraph::DrawableGroup3D _drawables;\n        GL::Mesh _mesh{NoCreate};\n        Containers::Optional<ArcBallCamera> _arcballCamera;\n\n        /* Stuff for visualizing the cube */\n        Shaders::MeshVisualizer3D _shader{NoCreate};\n        GL::Texture2D _colormap{NoCreate};\n};\n\nclass VisualizationDrawable: public SceneGraph::Drawable3D {\n    public:\n        explicit VisualizationDrawable(Object3D& object,\n            Shaders::MeshVisualizer3D& shader, GL::Mesh& mesh,\n            SceneGraph::DrawableGroup3D& drawables):\n                SceneGraph::Drawable3D{object, &drawables}, _shader(shader),\n                _mesh(mesh) {}\n\n        void draw(const Matrix4& transformation, SceneGraph::Camera3D& camera) {\n            _shader\n                .setTransformationMatrix(transformation)\n                .setProjectionMatrix(camera.projectionMatrix())\n                .draw(_mesh);\n        }\n\n    private:\n        Shaders::MeshVisualizer3D& _shader;\n        GL::Mesh& _mesh;\n};\n\nArcBallExample::ArcBallExample(const Arguments& arguments) :\n    Platform::Application{arguments, NoCreate}\n{\n    /* Setup window */\n    {\n        const Vector2 dpiScaling = this->dpiScaling({});\n        Configuration conf;\n        conf.setTitle(\"Magnum ArcBall Camera Example\")\n            .setSize(conf.size(), dpiScaling)\n            .setWindowFlags(Configuration::WindowFlag::Resizable);\n        GLConfiguration glConf;\n        glConf.setSampleCount(dpiScaling.max() < 2.0f ? 8 : 2);\n        if(!tryCreate(conf, glConf)) {\n            create(conf, glConf.setSampleCount(0));\n        }\n    }\n\n    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);\n    GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);\n\n    /* Setup a cube with vertex ID and wireframe visualized */\n    {\n        const Trade::MeshData cube = Primitives::cubeSolid();\n        _mesh = MeshTools::compile(cube);\n\n        const auto map = DebugTools::ColorMap::turbo();\n        const Vector2i size{Int(map.size()), 1};\n        _colormap = GL::Texture2D{};\n        _colormap\n            .setMinificationFilter(SamplerFilter::Linear)\n            .setMagnificationFilter(SamplerFilter::Linear)\n            .setWrapping(SamplerWrapping::ClampToEdge)\n            .setStorage(1, GL::TextureFormat::RGB8, size)\n            .setSubImage(0, {}, ImageView2D{PixelFormat::RGB8Unorm, size, map});\n\n        _shader = Shaders::MeshVisualizer3D{\n            Shaders::MeshVisualizer3D::Flag::Wireframe|\n            Shaders::MeshVisualizer3D::Flag::VertexId};\n        _shader\n            .setViewportSize(Vector2{framebufferSize()})\n            .setColor(0xffffff_rgbf)\n            .setWireframeColor(0xffffff_rgbf)\n            .setWireframeWidth(2.0f)\n            .setColorMapTransformation(0.0f, 1.0f/cube.vertexCount())\n            .bindColorMapTexture(_colormap);\n\n        auto object = new Object3D{&_scene};\n        (*object)\n            .rotateY(40.0_degf)\n            .rotateX(-30.0_degf)\n            ;\n        new VisualizationDrawable{*object, _shader, _mesh, _drawables};\n    }\n\n    /* Set up the camera */\n    {\n        /* Setup the arcball after the camera objects */\n        const Vector3 eye = Vector3::zAxis(-10.0f);\n        const Vector3 center{};\n        const Vector3 up = Vector3::yAxis();\n        _arcballCamera.emplace(_scene, eye, center, up, 45.0_degf,\n            windowSize(), framebufferSize());\n    }\n\n    /* Loop at 60 Hz max */\n    setSwapInterval(1);\n    setMinimalLoopPeriod(16);\n}\n\nvoid ArcBallExample::drawEvent() {\n    GL::defaultFramebuffer.clear(\n        GL::FramebufferClear::Color|GL::FramebufferClear::Depth);\n\n    /* Call arcball update in every frame. This will do nothing if the camera\n       has not been changed. Otherwise, camera transformation will be\n       propagated into the camera objects. */\n    bool camChanged = _arcballCamera->update();\n    _arcballCamera->draw(_drawables);\n    swapBuffers();\n\n    if(camChanged) redraw();\n}\n\nvoid ArcBallExample::viewportEvent(ViewportEvent& event) {\n    GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()});\n\n    _arcballCamera->reshape(event.windowSize(), event.framebufferSize());\n    _shader.setViewportSize(Vector2{framebufferSize()});\n}\n\nvoid ArcBallExample::keyPressEvent(KeyEvent& event) {\n    switch(event.key()) {\n        case KeyEvent::Key::L:\n            if(_arcballCamera->lagging() > 0.0f) {\n                Debug{} << \"Lagging disabled\";\n                _arcballCamera->setLagging(0.0f);\n            } else {\n                Debug{} << \"Lagging enabled\";\n                _arcballCamera->setLagging(0.85f);\n            }\n            break;\n        case KeyEvent::Key::R:\n            _arcballCamera->reset();\n            break;\n\n        default: return;\n    }\n\n    event.setAccepted();\n    redraw(); /* camera has changed, redraw! */\n}\n\nvoid ArcBallExample::mousePressEvent(MouseEvent& event) {\n    /* Enable mouse capture so the mouse can drag outside of the window */\n    /** @todo replace once https://github.com/mosra/magnum/pull/419 is in */\n    SDL_CaptureMouse(SDL_TRUE);\n\n    _arcballCamera->initTransformation(event.position());\n\n    event.setAccepted();\n    redraw(); /* camera has changed, redraw! */\n}\n\nvoid ArcBallExample::mouseReleaseEvent(MouseEvent&) {\n    /* Disable mouse capture again */\n    /** @todo replace once https://github.com/mosra/magnum/pull/419 is in */\n    SDL_CaptureMouse(SDL_FALSE);\n}\n\nvoid ArcBallExample::mouseMoveEvent(MouseMoveEvent& event) {\n    if(!event.buttons()) return;\n\n    if(event.modifiers() & MouseMoveEvent::Modifier::Shift)\n        _arcballCamera->translate(event.position());\n    else _arcballCamera->rotate(event.position());\n\n    event.setAccepted();\n    redraw(); /* camera has changed, redraw! */\n}\n\nvoid ArcBallExample::mouseScrollEvent(MouseScrollEvent& event) {\n    const Float delta = event.offset().y();\n    if(Math::abs(delta) < 1.0e-2f) return;\n\n    _arcballCamera->zoom(delta);\n\n    event.setAccepted();\n    redraw(); /* camera has changed, redraw! */\n}\n\n}}\n\nMAGNUM_APPLICATION_MAIN(Magnum::Examples::ArcBallExample)\n"
  },
  {
    "path": "src/examples/arcball/CMakeLists.txt",
    "content": "#\n#   This file is part of Magnum.\n#\n#   Original authors — credit is appreciated but not required:\n#\n#       2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 —\n#           Vladimír Vondruš <mosra@centrum.cz>\n#       2020 — Nghia Truong <nghiatruong.vn@gmail.com>\n#\n#   This is free and unencumbered software released into the public domain.\n#\n#   Anyone is free to copy, modify, publish, use, compile, sell, or distribute\n#   this software, either in source code form or as a compiled binary, for any\n#   purpose, commercial or non-commercial, and by any means.\n#\n#   In jurisdictions that recognize copyright laws, the author or authors of\n#   this software dedicate any and all copyright interest in the software to\n#   the public domain. We make this dedication for the benefit of the public\n#   at large and to the detriment of our heirs and successors. We intend this\n#   dedication to be an overt act of relinquishment in perpetuity of all\n#   present and future rights to this software under copyright law.\n#\n#   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n#   THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n#   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n#   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n#\n\ncmake_minimum_required(VERSION 3.4)\n\nproject(MagnumArcBallExample CXX)\n\n# Add module path in case this is project root\nif(PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)\n    set(CMAKE_MODULE_PATH \"${PROJECT_SOURCE_DIR}/../../modules/\" ${CMAKE_MODULE_PATH})\nendif()\n\nfind_package(Corrade REQUIRED Main)\nfind_package(Magnum REQUIRED\n    DebugTools\n    GL\n    MeshTools\n    Primitives\n    SceneGraph\n    Shaders\n    Sdl2Application)\n\nset_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)\n\nadd_executable(magnum-arcball WIN32\n    ArcBall.cpp\n    ArcBallExample.cpp)\ntarget_link_libraries(magnum-arcball PRIVATE\n    Corrade::Main\n    Magnum::Application\n    Magnum::DebugTools\n    Magnum::GL\n    Magnum::Magnum\n    Magnum::MeshTools\n    Magnum::Primitives\n    Magnum::SceneGraph\n    Magnum::Shaders)\n\ninstall(TARGETS magnum-arcball DESTINATION ${MAGNUM_BINARY_INSTALL_DIR})\n\n# Make the executable a default target to build & run in Visual Studio\nset_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT magnum-arcball)\n"
  },
  {
    "path": "src/examples/bullet_example/CMakeLists.txt",
    "content": "add_executable(bullet_example WIN32 bullet_example.cpp)\ntarget_link_libraries(bullet_example PRIVATE\n        Corrade::Main\n        Magnum::Application\n        Magnum::GL\n        Magnum::Magnum\n        Magnum::MeshTools\n        Magnum::Primitives\n        Magnum::SceneGraph\n        Magnum::Shaders\n        Magnum::Trade\n        MagnumIntegration::Bullet\n)\n"
  },
  {
    "path": "src/examples/bullet_example/bullet_example.cpp",
    "content": "/*\n    This file is part of Magnum.\n\n    Original authors — credit is appreciated but not required:\n\n        2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 —\n            Vladimír Vondruš <mosra@centrum.cz>\n        2013 — Jan Dupal <dupal.j@gmail.com>\n        2019 — Max Schwarz <max.schwarz@online.de>\n\n    This is free and unencumbered software released into the public domain.\n\n    Anyone is free to copy, modify, publish, use, compile, sell, or distribute\n    this software, either in source code form or as a compiled binary, for any\n    purpose, commercial or non-commercial, and by any means.\n\n    In jurisdictions that recognize copyright laws, the author or authors of\n    this software dedicate any and all copyright interest in the software to\n    the public domain. We make this dedication for the benefit of the public\n    at large and to the detriment of our heirs and successors. We intend this\n    dedication to be an overt act of relinquishment in perpetuity of all\n    present and future rights to this software under copyright law.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n    THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#include <btBulletDynamicsCommon.h>\n#include <Corrade/Containers/GrowableArray.h>\n#include <Corrade/Containers/Optional.h>\n#include <Corrade/Containers/Pointer.h>\n#include <Magnum/Timeline.h>\n#include <Magnum/BulletIntegration/Integration.h>\n#include <Magnum/BulletIntegration/MotionState.h>\n#include <Magnum/BulletIntegration/DebugDraw.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n#include <Magnum/GL/Mesh.h>\n#include <Magnum/GL/Renderer.h>\n#include <Magnum/Math/Constants.h>\n#include <Magnum/Math/Color.h>\n#include <Magnum/MeshTools/Compile.h>\n#include <Magnum/MeshTools/Transform.h>\n#include <Magnum/Platform/Sdl2Application.h>\n#include <Magnum/Primitives/Cube.h>\n#include <Magnum/Primitives/UVSphere.h>\n#include <Magnum/SceneGraph/Camera.h>\n#include <Magnum/SceneGraph/Drawable.h>\n#include <Magnum/SceneGraph/MatrixTransformation3D.h>\n#include <Magnum/SceneGraph/Scene.h>\n#include <Magnum/Shaders/Phong.h>\n#include <Magnum/Trade/MeshData.h>\n\nnamespace Magnum { namespace Examples {\n\nusing namespace Math::Literals;\n\ntypedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;\ntypedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D> Scene3D;\n\nstruct InstanceData {\n    Matrix4 transformationMatrix;\n    Matrix3x3 normalMatrix;\n    Color3 color;\n};\n\nclass BulletDummy: public Platform::Application {\npublic:\n    explicit BulletDummy(const Arguments& arguments);\n\nprivate:\n    void drawEvent() override;\n    void keyPressEvent(KeyEvent& event) override;\n    void mousePressEvent(MouseEvent& event) override;\n\n    GL::Mesh _box{NoCreate}, _sphere{NoCreate};\n    GL::Buffer _boxInstanceBuffer{NoCreate}, _sphereInstanceBuffer{NoCreate};\n    Shaders::Phong _shader{NoCreate};\n    BulletIntegration::DebugDraw _debugDraw{NoCreate};\n    Containers::Array<InstanceData> _boxInstanceData, _sphereInstanceData;\n\n    btDbvtBroadphase _bBroadphase;\n    btDefaultCollisionConfiguration _bCollisionConfig;\n    btCollisionDispatcher _bDispatcher{&_bCollisionConfig};\n    btSequentialImpulseConstraintSolver _bSolver;\n\n    /* The world has to live longer than the scene because RigidBody\n       instances have to remove themselves from it on destruction */\n    btDiscreteDynamicsWorld _bWorld{&_bDispatcher, &_bBroadphase, &_bSolver, &_bCollisionConfig};\n\n    Scene3D _scene;\n    SceneGraph::Camera3D* _camera;\n    SceneGraph::DrawableGroup3D _drawables;\n    Timeline _timeline;\n\n    Object3D *_cameraRig, *_cameraObject;\n\n    btBoxShape _bBoxShape{{0.5f, 0.5f, 0.5f}};\n    btSphereShape _bSphereShape{0.25f};\n    btBoxShape _bGroundShape{{4.0f, 0.5f, 4.0f}};\n\n    bool _drawCubes{true}, _drawDebug{true}, _shootBox{true};\n};\n\nclass ColoredDrawable: public SceneGraph::Drawable3D {\npublic:\n    explicit ColoredDrawable(Object3D& object, Containers::Array<InstanceData>& instanceData, const Color3& color, const Matrix4& primitiveTransformation, SceneGraph::DrawableGroup3D& drawables): SceneGraph::Drawable3D{object, &drawables}, _instanceData(instanceData), _color{color}, _primitiveTransformation{primitiveTransformation} {}\n\nprivate:\n    void draw(const Matrix4& transformation, SceneGraph::Camera3D&) override {\n        const Matrix4 t = transformation*_primitiveTransformation;\n        arrayAppend(_instanceData, Containers::InPlaceInit,\n                    t, t.normalMatrix(), _color);\n    }\n\n    Containers::Array<InstanceData>& _instanceData;\n    Color3 _color;\n    Matrix4 _primitiveTransformation;\n};\n\nclass RigidBody: public Object3D {\npublic:\n    RigidBody(Object3D* parent, Float mass, btCollisionShape* bShape, btDynamicsWorld& bWorld): Object3D{parent}, _bWorld(bWorld) {\n        /* Calculate inertia so the object reacts as it should with\n           rotation and everything */\n        btVector3 bInertia(0.0f, 0.0f, 0.0f);\n        if(!Math::TypeTraits<Float>::equals(mass, 0.0f))\n            bShape->calculateLocalInertia(mass, bInertia);\n\n        /* Bullet rigid body setup */\n        auto* motionState = new BulletIntegration::MotionState{*this};\n        _bRigidBody.emplace(btRigidBody::btRigidBodyConstructionInfo{\n            mass, &motionState->btMotionState(), bShape, bInertia});\n        _bRigidBody->forceActivationState(DISABLE_DEACTIVATION);\n        bWorld.addRigidBody(_bRigidBody.get());\n    }\n\n    ~RigidBody() {\n        _bWorld.removeRigidBody(_bRigidBody.get());\n    }\n\n    btRigidBody& rigidBody() { return *_bRigidBody; }\n\n    /* needed after changing the pose from Magnum side */\n    void syncPose() {\n        _bRigidBody->setWorldTransform(btTransform(transformationMatrix()));\n    }\n\nprivate:\n    btDynamicsWorld& _bWorld;\n    Containers::Pointer<btRigidBody> _bRigidBody;\n};\n\nBulletDummy::BulletDummy(const Arguments& arguments): Platform::Application(arguments, NoCreate) {\n    /* Try 8x MSAA, fall back to zero samples if not possible. Enable only 2x\n       MSAA if we have enough DPI. */\n    {\n        const Vector2 dpiScaling = this->dpiScaling({});\n        Configuration conf;\n        conf.setTitle(\"Magnum Bullet Integration Example\")\n            .setSize(conf.size(), dpiScaling);\n        GLConfiguration glConf;\n        glConf.setSampleCount(dpiScaling.max() < 2.0f ? 8 : 2);\n        if(!tryCreate(conf, glConf))\n            create(conf, glConf.setSampleCount(0));\n    }\n\n    /* Camera setup */\n    (*(_cameraRig = new Object3D{&_scene}))\n        .translate(Vector3::yAxis(3.0f))\n        .rotateY(40.0_degf);\n    (*(_cameraObject = new Object3D{_cameraRig}))\n        .translate(Vector3::zAxis(20.0f))\n        .rotateX(-25.0_degf);\n    (_camera = new SceneGraph::Camera3D(*_cameraObject))\n        ->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)\n        .setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 1.0f, 0.001f, 100.0f))\n        .setViewport(GL::defaultFramebuffer.viewport().size());\n\n    /* Create an instanced shader */\n    _shader = Shaders::Phong{\n        Shaders::Phong::Flag::VertexColor|\n        Shaders::Phong::Flag::InstancedTransformation};\n    _shader.setAmbientColor(0x111111_rgbf)\n           .setSpecularColor(0x330000_rgbf)\n           .setLightPosition({10.0f, 15.0f, 5.0f});\n\n    /* Box and sphere mesh, with an (initially empty) instance buffer */\n    _box = MeshTools::compile(Primitives::cubeSolid());\n    _sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32));\n    _boxInstanceBuffer = GL::Buffer{};\n    _sphereInstanceBuffer = GL::Buffer{};\n    _box.addVertexBufferInstanced(_boxInstanceBuffer, 1, 0,\n                                  Shaders::Phong::TransformationMatrix{},\n                                  Shaders::Phong::NormalMatrix{},\n                                  Shaders::Phong::Color3{});\n    _sphere.addVertexBufferInstanced(_sphereInstanceBuffer, 1, 0,\n                                     Shaders::Phong::TransformationMatrix{},\n                                     Shaders::Phong::NormalMatrix{},\n                                     Shaders::Phong::Color3{});\n\n    /* Setup the renderer so we can draw the debug lines on top */\n    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);\n    GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);\n    GL::Renderer::enable(GL::Renderer::Feature::PolygonOffsetFill);\n    GL::Renderer::setPolygonOffset(2.0f, 0.5f);\n\n    /* Bullet setup */\n    _debugDraw = BulletIntegration::DebugDraw{};\n    _debugDraw.setMode(BulletIntegration::DebugDraw::Mode::DrawWireframe);\n    _bWorld.setGravity({0.0f, -10.0f, 0.0f});\n    _bWorld.setDebugDrawer(&_debugDraw);\n\n    /* Create the ground */\n    auto* ground = new RigidBody{&_scene, 0.0f, &_bGroundShape, _bWorld};\n    new ColoredDrawable{*ground, _boxInstanceData, 0xffffff_rgbf,\n        Matrix4::scaling({4.0f, 0.5f, 4.0f}), _drawables};\n\n    /* Create boxes with random colors */\n    Deg hue = 42.0_degf;\n    for(Int i = 0; i != 5; ++i) {\n        for(Int j = 0; j != 5; ++j) {\n            for(Int k = 0; k != 5; ++k) {\n                auto* o = new RigidBody{&_scene, 1.0f, &_bBoxShape, _bWorld};\n                o->translate({i - 2.0f, j + 4.0f, k - 2.0f});\n                o->syncPose();\n                new ColoredDrawable{*o, _boxInstanceData,\n                    Color3::fromHsv({hue += 137.5_degf, 0.75f, 0.9f}),\n                    Matrix4::scaling(Vector3{0.5f}), _drawables};\n            }\n        }\n    }\n\n    /* Loop at 60 Hz max */\n    setSwapInterval(1);\n    setMinimalLoopPeriod(16);\n    _timeline.start();\n}\n\nvoid BulletDummy::drawEvent() {\n    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth);\n\n    /* Housekeeping: remove any objects which are far away from the origin */\n    for(Object3D* obj = _scene.children().first(); obj; )\n    {\n        Object3D* next = obj->nextSibling();\n        if(obj->transformation().translation().dot() > 100*100)\n            delete obj;\n\n        obj = next;\n    }\n\n    /* Step bullet simulation */\n    _bWorld.stepSimulation(_timeline.previousFrameDuration(), 5);\n\n    if(_drawCubes) {\n        /* Populate instance data with transformations and colors */\n        arrayResize(_boxInstanceData, 0);\n        arrayResize(_sphereInstanceData, 0);\n        _camera->draw(_drawables);\n\n        _shader.setProjectionMatrix(_camera->projectionMatrix());\n\n        /* Upload instance data to the GPU (orphaning the previous buffer\n           contents) and draw all cubes in one call, and all spheres (if any)\n           in another call */\n        _boxInstanceBuffer.setData(_boxInstanceData, GL::BufferUsage::DynamicDraw);\n        _box.setInstanceCount(_boxInstanceData.size());\n        _shader.draw(_box);\n\n        _sphereInstanceBuffer.setData(_sphereInstanceData, GL::BufferUsage::DynamicDraw);\n        _sphere.setInstanceCount(_sphereInstanceData.size());\n        _shader.draw(_sphere);\n    }\n\n    /* Debug draw. If drawing on top of cubes, avoid flickering by setting\n       depth function to <= instead of just <. */\n    if(_drawDebug) {\n        if(_drawCubes)\n            GL::Renderer::setDepthFunction(GL::Renderer::DepthFunction::LessOrEqual);\n\n        _debugDraw.setTransformationProjectionMatrix(\n            _camera->projectionMatrix()*_camera->cameraMatrix());\n        _bWorld.debugDrawWorld();\n\n        if(_drawCubes)\n            GL::Renderer::setDepthFunction(GL::Renderer::DepthFunction::Less);\n    }\n\n    swapBuffers();\n    _timeline.nextFrame();\n    redraw();\n}\n\nvoid BulletDummy::keyPressEvent(KeyEvent& event) {\n    /* Movement */\n    if(event.key() == KeyEvent::Key::Down) {\n        _cameraObject->rotateX(5.0_degf);\n    } else if(event.key() == KeyEvent::Key::Up) {\n        _cameraObject->rotateX(-5.0_degf);\n    } else if(event.key() == KeyEvent::Key::Left) {\n        _cameraRig->rotateY(-5.0_degf);\n    } else if(event.key() == KeyEvent::Key::Right) {\n        _cameraRig->rotateY(5.0_degf);\n\n        /* Toggling draw modes */\n    } else if(event.key() == KeyEvent::Key::D) {\n        if(_drawCubes && _drawDebug) {\n            _drawDebug = false;\n        } else if(_drawCubes && !_drawDebug) {\n            _drawCubes = false;\n            _drawDebug = true;\n        } else if(!_drawCubes && _drawDebug) {\n            _drawCubes = true;\n            _drawDebug = true;\n        }\n\n        /* What to shoot */\n    } else if(event.key() == KeyEvent::Key::S) {\n        _shootBox ^= true;\n    } else return;\n\n    event.setAccepted();\n}\n\nvoid BulletDummy::mousePressEvent(MouseEvent& event) {\n    /* Shoot an object on click */\n    if(event.button() == MouseEvent::Button::Left) {\n        /* First scale the position from being relative to window size to being\n           relative to framebuffer size as those two can be different on HiDPI\n           systems */\n        const Vector2i position = event.position()*Vector2{framebufferSize()}/Vector2{windowSize()};\n        const Vector2 clickPoint = Vector2::yScale(-1.0f)*(Vector2{position}/Vector2{framebufferSize()} - Vector2{0.5f})*_camera->projectionSize();\n        const Vector3 direction = (_cameraObject->absoluteTransformation().rotationScaling()*Vector3{clickPoint, -1.0f}).normalized();\n\n        auto* object = new RigidBody{\n            &_scene,\n            _shootBox ? 1.0f : 5.0f,\n            _shootBox ? static_cast<btCollisionShape*>(&_bBoxShape) : &_bSphereShape,\n            _bWorld};\n        object->translate(_cameraObject->absoluteTransformation().translation());\n        /* Has to be done explicitly after the translate() above, as Magnum ->\n           Bullet updates are implicitly done only for kinematic bodies */\n        object->syncPose();\n\n        /* Create either a box or a sphere */\n        new ColoredDrawable{*object,\n            _shootBox ? _boxInstanceData : _sphereInstanceData,\n            _shootBox ? 0x880000_rgbf : 0x220000_rgbf,\n            Matrix4::scaling(Vector3{_shootBox ? 0.5f : 0.25f}), _drawables};\n\n        /* Give it an initial velocity */\n        object->rigidBody().setLinearVelocity(btVector3{direction*25.f});\n\n        event.setAccepted();\n    }\n}\n\n}}\n\nMAGNUM_APPLICATION_MAIN(Magnum::Examples::BulletDummy)\n"
  },
  {
    "path": "src/examples/picking_objects/CMakeLists.txt",
    "content": "add_executable(picking_example picking_example.cpp)\ntarget_link_libraries(picking_example PRIVATE\n        Corrade::Main\n        Magnum::Application\n        Magnum::GL\n        Magnum::Magnum\n        Magnum::MeshTools\n        Magnum::Primitives\n        Magnum::SceneGraph\n        Magnum::Shaders\n)"
  },
  {
    "path": "src/examples/picking_objects/picking_example.cpp",
    "content": "#include <Corrade/Containers/Reference.h>\n#include <Corrade/Utility/Resource.h>\n#include <Magnum/Image.h>\n#include <Magnum/PixelFormat.h>\n#include <Magnum/GL/Context.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n#include <Magnum/GL/Framebuffer.h>\n#include <Magnum/GL/Mesh.h>\n#include <Magnum/GL/Renderbuffer.h>\n#include <Magnum/GL/RenderbufferFormat.h>\n#include <Magnum/GL/Renderer.h>\n#include <Magnum/GL/Texture.h>\n#include <Magnum/GL/TextureFormat.h>\n#include <Magnum/GL/Version.h>\n#include <Magnum/Math/Color.h>\n#include <Magnum/MeshTools/Compile.h>\n#include <Magnum/Platform/Sdl2Application.h>\n#include <Magnum/Primitives/Cube.h>\n#include <Magnum/Primitives/Plane.h>\n#include <Magnum/Primitives/UVSphere.h>\n#include <Magnum/Trade/MeshData.h>\n#include <Magnum/SceneGraph/Scene.h>\n#include <Magnum/SceneGraph/MatrixTransformation3D.h>\n#include <Magnum/SceneGraph/Camera.h>\n#include <Magnum/SceneGraph/Drawable.h>\n#include <Magnum/Shaders/Phong.h>\n\nnamespace Magnum { namespace Examples {\n\nusing namespace Magnum::Math::Literals;\n\ntypedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;\ntypedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D> Scene3D;\n\nclass PickableObject: public Object3D, SceneGraph::Drawable3D {\npublic:\n    explicit PickableObject(UnsignedInt id, Shaders::Phong& shader, const Color3& color, GL::Mesh& mesh, Object3D& parent, SceneGraph::DrawableGroup3D& drawables):\n        Object3D{&parent}, SceneGraph::Drawable3D{*this, &drawables}, _id{id}, _selected{false}, _shader(shader), _color{color}, _mesh(mesh)\n    {}\n\n    void setSelected(bool selected) { _selected = selected; }\n\nprivate:\n    virtual void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) override {\n        _shader.setTransformationMatrix(transformationMatrix)\n                .setNormalMatrix(transformationMatrix.normalMatrix())\n                .setProjectionMatrix(camera.projectionMatrix())\n                .setAmbientColor(_selected ? _color*0.3f : Color3{})\n                .setDiffuseColor(_color*(_selected ? 2.0f : 1.0f))\n                        /* relative to the camera */\n                .setLightPosition({13.0f, 2.0f, 5.0f})\n                .setObjectId(_id)\n                .draw(_mesh);\n    }\n\n    UnsignedInt _id;\n    bool _selected;\n    Shaders::Phong& _shader;\n    Color3 _color;\n    GL::Mesh& _mesh;\n};\n\nclass PickingExample: public Platform::Application {\npublic:\n    explicit PickingExample(const Arguments& arguments);\n\nprivate:\n    void drawEvent() override;\n    void mousePressEvent(MouseEvent& event) override;\n    void mouseMoveEvent(MouseMoveEvent& event) override;\n    void mouseReleaseEvent(MouseEvent& event) override;\n\n    Scene3D _scene;\n    Object3D* _cameraObject;\n    SceneGraph::Camera3D* _camera;\n    SceneGraph::DrawableGroup3D _drawables;\n\n    Shaders::Phong _shader{Shaders::Phong::Flag::ObjectId};\n    GL::Mesh _cube, _plane, _sphere;\n\n    enum { ObjectCount = 6 };\n    PickableObject* _objects[ObjectCount];\n\n    GL::Framebuffer _framebuffer;\n    GL::Renderbuffer _color, _objectId, _depth;\n\n    Vector2i _previousMousePosition, _mousePressPosition;\n};\n\nPickingExample::PickingExample(const Arguments& arguments): Platform::Application{arguments, Configuration{}.setTitle(\"Magnum object picking_objects example\")}, _framebuffer{GL::defaultFramebuffer.viewport()} {\n    MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL330);\n\n    /* Global renderer configuration */\n    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);\n\n    /* Configure framebuffer. Using a 32-bit int for object ID, which is likely\n       enough. Use a smaller type if you have less objects to save memory. */\n    _color.setStorage(GL::RenderbufferFormat::RGBA8, GL::defaultFramebuffer.viewport().size());\n    _objectId.setStorage(GL::RenderbufferFormat::R32UI, GL::defaultFramebuffer.viewport().size());\n    _depth.setStorage(GL::RenderbufferFormat::DepthComponent24, GL::defaultFramebuffer.viewport().size());\n    _framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _color)\n            .attachRenderbuffer(GL::Framebuffer::ColorAttachment{1}, _objectId)\n            .attachRenderbuffer(GL::Framebuffer::BufferAttachment::Depth, _depth)\n            .mapForDraw({{Shaders::Phong::ColorOutput, GL::Framebuffer::ColorAttachment{0}},\n                         {Shaders::Phong::ObjectIdOutput, GL::Framebuffer::ColorAttachment{1}}});\n    CORRADE_INTERNAL_ASSERT(_framebuffer.checkStatus(GL::FramebufferTarget::Draw) == GL::Framebuffer::Status::Complete);\n\n    /* Set up meshes */\n    _cube = MeshTools::compile(Primitives::cubeSolid());\n    _sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32));\n    _plane = MeshTools::compile(Primitives::planeSolid());\n\n    /* Set up objects */\n    (*(_objects[0] = new PickableObject{1, _shader, 0x3bd267_rgbf, _cube, _scene, _drawables}))\n            .rotate(34.0_degf, Vector3(1.0f).normalized())\n            .translate({1.0f, 0.3f, -1.2f});\n    (*(_objects[1] = new PickableObject{2, _shader, 0x2f83cc_rgbf, _sphere, _scene, _drawables}))\n            .translate({-1.2f, -0.3f, -0.2f});\n    (*(_objects[2] = new PickableObject{3, _shader, 0xdcdcdc_rgbf, _plane, _scene, _drawables}))\n            .rotate(278.0_degf, Vector3(1.0f).normalized())\n            .scale(Vector3(0.45f))\n            .translate({-1.0f, 1.2f, 1.5f});\n    (*(_objects[3] = new PickableObject{4, _shader, 0xc7cf2f_rgbf, _sphere, _scene, _drawables}))\n            .translate({-0.2f, -1.7f, -2.7f});\n    (*(_objects[4] = new PickableObject{5, _shader, 0xcd3431_rgbf, _sphere, _scene, _drawables}))\n            .translate({0.7f, 0.6f, 2.2f})\n            .scale(Vector3(0.75f));\n    (*(_objects[5] = new PickableObject{6, _shader, 0xa5c9ea_rgbf, _cube, _scene, _drawables}))\n            .rotate(-92.0_degf, Vector3(1.0f).normalized())\n            .scale(Vector3(0.25f))\n            .translate({-0.5f, -0.3f, 1.8f});\n\n    /* Configure camera */\n    _cameraObject = new Object3D{&_scene};\n    _cameraObject->translate(Vector3::zAxis(8.0f));\n    _camera = new SceneGraph::Camera3D{*_cameraObject};\n    _camera->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)\n            .setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 4.0f/3.0f, 0.001f, 100.0f))\n            .setViewport(GL::defaultFramebuffer.viewport().size());\n}\n\nvoid PickingExample::drawEvent() {\n    /* Draw to custom framebuffer */\n    _framebuffer\n            .clearColor(0, Color3{0.125f})\n            .clearColor(1, Vector4ui{})\n            .clearDepth(1.0f)\n            .bind();\n    _camera->draw(_drawables);\n\n    /* Bind the main buffer back */\n    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color|GL::FramebufferClear::Depth)\n            .bind();\n\n    /* Blit color to window framebuffer */\n    _framebuffer.mapForRead(GL::Framebuffer::ColorAttachment{0});\n    GL::AbstractFramebuffer::blit(_framebuffer, GL::defaultFramebuffer,\n                                  {{}, _framebuffer.viewport().size()}, GL::FramebufferBlit::Color);\n\n    swapBuffers();\n}\n\nvoid PickingExample::mousePressEvent(MouseEvent& event) {\n    if(event.button() != MouseEvent::Button::Left) return;\n\n    _previousMousePosition = _mousePressPosition = event.position();\n    event.setAccepted();\n}\n\nvoid PickingExample::mouseMoveEvent(MouseMoveEvent& event) {\n    if(!(event.buttons() & MouseMoveEvent::Button::Left)) return;\n\n    /* We have to take window size, not framebuffer size, since the position is\n       in window coordinates and the two can be different on HiDPI systems */\n    const Vector2 delta = 3.0f*\n                          Vector2{event.position() - _previousMousePosition}/\n                          Vector2{windowSize()};\n\n    (*_cameraObject)\n            .rotate(Rad{-delta.y()}, _cameraObject->transformation().right().normalized())\n            .rotateY(Rad{-delta.x()});\n\n    _previousMousePosition = event.position();\n    event.setAccepted();\n    redraw();\n}\n\nvoid PickingExample::mouseReleaseEvent(MouseEvent& event) {\n    if(event.button() != MouseEvent::Button::Left || _mousePressPosition != event.position()) return;\n\n    /* First scale the position from being relative to window size to being\n       relative to framebuffer size as those two can be different on HiDPI\n       systems */\n    const Vector2i position = event.position()*Vector2{framebufferSize()}/Vector2{windowSize()};\n    const Vector2i fbPosition{position.x(), GL::defaultFramebuffer.viewport().sizeY() - position.y() - 1};\n\n    /* Read object ID at given click position */\n    _framebuffer.mapForRead(GL::Framebuffer::ColorAttachment{1});\n    Image2D data = _framebuffer.read(\n            Range2Di::fromSize(fbPosition, {1, 1}),\n            {PixelFormat::R32UI});\n\n    /* Highlight object under mouse and deselect all other */\n    for(auto* o: _objects) o->setSelected(false);\n    UnsignedInt id = Containers::arrayCast<UnsignedInt>(data.data())[0];\n    if(id > 0 && id < ObjectCount + 1)\n        _objects[id - 1]->setSelected(true);\n\n    event.setAccepted();\n    redraw();\n}\n\n}}\n\nMAGNUM_APPLICATION_MAIN(Magnum::Examples::PickingExample)\n"
  },
  {
    "path": "src/examples/textured_triangle/CMakeLists.txt",
    "content": "corrade_add_resource(TexturedTriangle_RESOURCES resources.conf)\n\nadd_executable(textured_triangle textured_triangle.cpp textured_triangle_shader.cpp ${TexturedTriangle_RESOURCES})\ntarget_link_libraries(textured_triangle PRIVATE\n        Corrade::Main\n        Magnum::Application\n        Magnum::GL\n        Magnum::Magnum\n        Magnum::Trade\n        )\n\n# So the TgaImporter gets built implicitly\nadd_dependencies(textured_triangle Magnum::TgaImporter)\n"
  },
  {
    "path": "src/examples/textured_triangle/resources.conf",
    "content": "group=textured-triangle-data\n\n[file]\nfilename=textured_triangle_shader.frag\n\n[file]\nfilename=textured_triangle_shader.vert\n\n[file]\nfilename=stone.tga\n"
  },
  {
    "path": "src/examples/textured_triangle/textured_triangle.cpp",
    "content": "#include <Corrade/Containers/ArrayView.h>\n#include <Corrade/Containers/Optional.h>\n#include <Corrade/PluginManager/Manager.h>\n#include <Corrade/Utility/Resource.h>\n#include <Magnum/ImageView.h>\n#include <Magnum/GL/Buffer.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n#include <Magnum/GL/Mesh.h>\n#include <Magnum/GL/Texture.h>\n#include <Magnum/GL/TextureFormat.h>\n#include <Magnum/Platform/Sdl2Application.h>\n#include <Magnum/Trade/AbstractImporter.h>\n#include <Magnum/Trade/ImageData.h>\n\n#include \"textured_triangle_shader.hpp\"\n\n\nusing namespace Magnum;\n\n\nclass TexturedTriangleExample: public Platform::Application {\npublic:\n    explicit TexturedTriangleExample(const Arguments& arguments);\n\nprivate:\n    void drawEvent() override;\n\n    GL::Mesh _mesh;\n    TexturedTriangleShader _shader;\n    GL::Texture2D _texture;\n};\n\nTexturedTriangleExample::TexturedTriangleExample(const Arguments& arguments):\n        Platform::Application{arguments, Configuration{}\n                .setTitle(\"Magnum Textured Triangle Example\")}\n{\n    struct TriangleVertex {\n        Vector2 position;\n        Vector2 textureCoordinates;\n    };\n    const TriangleVertex data[]{\n            {{-0.5f, -0.5f}, {0.0f, 0.0f}}, /* Left position and texture coordinate */\n            {{ 0.5f, -0.5f}, {1.0f, 0.0f}}, /* Right position and texture coordinate */\n            {{ 0.0f,  0.5f}, {0.5f, 1.0f}}  /* Top position and texture coordinate */\n    };\n\n    GL::Buffer buffer;\n    buffer.setData(data);\n    _mesh.setCount(3)\n            .addVertexBuffer(std::move(buffer), 0,\n                             TexturedTriangleShader::Position{},\n                             TexturedTriangleShader::TextureCoordinates{});\n\n    PluginManager::Manager<Trade::AbstractImporter> manager;\n    Containers::Pointer<Trade::AbstractImporter> importer =\n            manager.loadAndInstantiate(\"TgaImporter\");\n    if(!importer) std::exit(1);\n\n    const Utility::Resource rs{\"textured-triangle-data\"};\n    if(!importer->openData(rs.getRaw(\"stone.tga\")))\n        std::exit(2);\n\n    Containers::Optional<Trade::ImageData2D> image = importer->image2D(0);\n    CORRADE_INTERNAL_ASSERT(image);\n    _texture.setWrapping(GL::SamplerWrapping::ClampToEdge)\n            .setMagnificationFilter(GL::SamplerFilter::Linear)\n            .setMinificationFilter(GL::SamplerFilter::Linear)\n            .setStorage(1, GL::textureFormat(image->format()), image->size())\n            .setSubImage(0, {}, *image);\n}\n\nvoid TexturedTriangleExample::drawEvent() {\n    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);\n\n    using namespace Math::Literals;\n\n    _shader\n            .setColor(0xffb2b2_rgbf)\n            .bindTexture(_texture)\n            .draw(_mesh);\n\n    swapBuffers();\n}\n\nMAGNUM_APPLICATION_MAIN(TexturedTriangleExample)"
  },
  {
    "path": "src/examples/textured_triangle/textured_triangle_shader.cpp",
    "content": "#include \"textured_triangle_shader.hpp\"\n\n#include <Corrade/Containers/Reference.h>\n#include <Corrade/Utility/Resource.h>\n#include <Magnum/GL/Context.h>\n#include <Magnum/GL/Shader.h>\n#include <Magnum/GL/Version.h>\n\nnamespace Magnum {\n\nTexturedTriangleShader::TexturedTriangleShader() {\n    MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL330);\n\n    const Utility::Resource rs{\"textured-triangle-data\"};\n\n    GL::Shader vert{GL::Version::GL330, GL::Shader::Type::Vertex};\n    GL::Shader frag{GL::Version::GL330, GL::Shader::Type::Fragment};\n\n    vert.addSource(rs.get(\"textured_triangle_shader.vert\"));\n    frag.addSource(rs.get(\"textured_triangle_shader.frag\"));\n\n    CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag}));\n\n    attachShaders({vert, frag});\n\n    CORRADE_INTERNAL_ASSERT_OUTPUT(link());\n\n    _colorUniform = uniformLocation(\"color\");\n\n    setUniform(uniformLocation(\"textureData\"), TextureUnit);\n}\n\n}"
  },
  {
    "path": "src/examples/textured_triangle/textured_triangle_shader.frag",
    "content": "uniform vec3 color = vec3(1.0, 1.0, 1.0);\nuniform sampler2D textureData;\n\nin vec2 interpolatedTextureCoordinates;\n\nout vec4 fragmentColor;\n\nvoid main() {\n    fragmentColor.rgb = color*texture(textureData, interpolatedTextureCoordinates).rgb;\n    fragmentColor.a = 1.0;\n}"
  },
  {
    "path": "src/examples/textured_triangle/textured_triangle_shader.hpp",
    "content": "#pragma once\n\n\n#include <Magnum/GL/AbstractShaderProgram.h>\n#include <Magnum/GL/Texture.h>\n#include <Magnum/Math/Color.h>\n\nnamespace Magnum {\n\nclass TexturedTriangleShader: public GL::AbstractShaderProgram {\npublic:\n    typedef GL::Attribute<0, Vector2> Position;\n    typedef GL::Attribute<1, Vector2> TextureCoordinates;\n\n    explicit TexturedTriangleShader();\n\n    TexturedTriangleShader& setColor(const Color3& color) {\n        setUniform(_colorUniform, color);\n        return *this;\n    }\n\n    TexturedTriangleShader& bindTexture(GL::Texture2D& texture) {\n        texture.bind(TextureUnit);\n        return *this;\n    }\n\nprivate:\n    enum: Int { TextureUnit = 0 };\n\n    Int _colorUniform;\n};\n\n}"
  },
  {
    "path": "src/examples/textured_triangle/textured_triangle_shader.vert",
    "content": "layout(location = 0) in vec4 position;\nlayout(location = 1) in vec2 textureCoordinates;\n\nout vec2 interpolatedTextureCoordinates;\n\nvoid main() {\n    interpolatedTextureCoordinates = textureCoordinates;\n\n    gl_Position = position;\n}\n"
  },
  {
    "path": "src/examples/triangle.cpp",
    "content": "#include <Magnum/GL/Buffer.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n#include <Magnum/GL/Mesh.h>\n#include <Magnum/Math/Color.h>\n#include <Magnum/Platform/Sdl2Application.h>\n#include <Magnum/Shaders/VertexColor.h>\n\nusing namespace Magnum;\n\nclass TriangleExample: public Platform::Application {\npublic:\n    explicit TriangleExample(const Arguments& arguments);\n\nprivate:\n    void drawEvent() override;\n\n    GL::Mesh _mesh;\n    Shaders::VertexColor2D _shader;\n};\n\nTriangleExample::TriangleExample(const Arguments& arguments):\n        Platform::Application{arguments, Configuration{}.setTitle(\"Magnum Triangle Example\")}\n{\n    using namespace Math::Literals;\n\n    struct TriangleVertex {\n        Vector2 position;\n        Color3 color;\n    };\n    const TriangleVertex data[]{\n            {{-0.5f, -0.5f}, 0xff0000_rgbf},    /* Left vertex, red color */\n            {{ 0.5f, -0.5f}, 0x00ff00_rgbf},    /* Right vertex, green color */\n            {{ 0.0f,  0.5f}, 0x0000ff_rgbf}     /* Top vertex, blue color */\n    };\n\n    GL::Buffer buffer;\n    buffer.setData(data);\n\n    _mesh.setCount(3)\n         .addVertexBuffer(std::move(buffer), 0, Shaders::VertexColor2D::Position{}, Shaders::VertexColor2D::Color3{});\n}\n\nvoid TriangleExample::drawEvent() {\n    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);\n\n    _shader.draw(_mesh);\n\n    swapBuffers();\n}\n\nMAGNUM_APPLICATION_MAIN(TriangleExample)\n"
  },
  {
    "path": "src/libs/CMakeLists.txt",
    "content": "find_package(Corrade REQUIRED Main)\n\nadd_subdirectory(util)\nadd_subdirectory(rendering)\nadd_subdirectory(magnum_rendering)\nif (NOT CORRADE_TARGET_APPLE)\n    add_subdirectory(v4r_rendering)\nendif ()\nadd_subdirectory(env)\nadd_subdirectory(mazes)\nadd_subdirectory(scenarios)\nadd_subdirectory(viewer)\nadd_subdirectory(bindings)\n"
  },
  {
    "path": "src/libs/bindings/CMakeLists.txt",
    "content": "find_package(Corrade REQUIRED Main)\n\nif (BUILD_GUI_APPS)\n    add_definitions(-DWITH_GUI=1)\nendif()\n\npybind11_add_module(megaverse megaverse.cpp)\ntarget_link_libraries(megaverse PUBLIC scenarios magnum_rendering)\n\nif (NOT CORRADE_TARGET_APPLE)\n    target_link_libraries(megaverse PUBLIC v4r_rendering)\nendif ()\n\nif (BUILD_GUI_APPS)\n    target_link_libraries(megaverse PUBLIC viewer Magnum::Application)\nendif()\n"
  },
  {
    "path": "src/libs/bindings/megaverse.cpp",
    "content": "#include <pybind11/stl.h>\n#include <pybind11/numpy.h>\n#include <pybind11/pybind11.h>\n\n#include <opencv2/core/mat.hpp>\n\n#include <util/tiny_logger.hpp>\n\n#include <env/env.hpp>\n\n#include <scenarios/init.hpp>\n\n#include <magnum_rendering/magnum_env_renderer.hpp>\n\n#ifndef CORRADE_TARGET_APPLE\n    #include <v4r_rendering/v4r_env_renderer.hpp>\n#endif\n\n#ifdef WITH_GUI\n    #include <viewer/viewer.hpp>\n#endif\n\n\nnamespace py = pybind11;\n\nusing namespace Megaverse;\n\n\nvoid setMegaverseLogLevel(int level)\n{\n    setLogLevel(LogLevel(level));\n}\n\n\nclass MegaverseGym\n{\npublic:\n    MegaverseGym(\n        const std::string &scenario,\n        int w, int h,\n        int numEnvs, int numAgentsPerEnv, int numSimulationThreads,\n        bool useVulkan,\n        const std::map<std::string, float> &floatParams\n    )\n        : numEnvs{numEnvs}\n          , numAgentsPerEnv{numAgentsPerEnv}\n          , useVulkan{useVulkan}\n          , w{w}\n          , h{h}\n          , numSimulationThreads{numSimulationThreads}\n    {\n        scenariosGlobalInit();\n\n        for (int i = 0; i < numEnvs; ++i)\n            envs.emplace_back(std::make_unique<Env>(scenario, numAgentsPerEnv, floatParams));\n\n        rewards = std::vector<float>(size_t(numEnvs * numAgentsPerEnv));\n    }\n\n    void seed(int seedValue)\n    {\n        TLOG(INFO) << \"Seeding vector env with seed value \" << seedValue;\n\n        rng.seed((unsigned long) seedValue);\n        for (auto &e : envs) {\n            const auto noise = randRange(0, 1 << 30, rng);\n            e->seed(noise);\n        }\n    }\n\n    int numAgents() const\n    {\n        return envs.front()->getNumAgents();\n    }\n\n    void reset()\n    {\n        if (!vectorEnv) {\n            if (useVulkan)\n#ifdef CORRADE_TARGET_APPLE\n                TLOG(ERROR) << \"Vulkan not supported on MacOS\";\n#else\n                renderer = std::make_unique<V4REnvRenderer>(envs, w, h, nullptr, false);\n#endif\n            else\n                renderer = std::make_unique<MagnumEnvRenderer>(envs, w, h);\n\n            vectorEnv = std::make_unique<VectorEnv>(envs, *renderer, numSimulationThreads);\n        }\n\n        // this also resets the main renderer\n        vectorEnv->reset();\n    }\n\n    std::vector<int> actionSpaceSizes() const\n    {\n        return Env::actionSpaceSizes;\n    }\n\n    void setActions(int envIdx, int agentIdx, std::vector<int> actions)\n    {\n        int actionIdx = 0, actionMask = 0;\n        const auto &spaces = Env::actionSpaceSizes;\n\n        for (int i = 0; i < int(actions.size()); ++i) {\n            const auto action = actions[i];\n\n            if (action > 0)\n                actionMask = actionMask | (1 << (actionIdx + action));\n\n            const auto numNonIdleActions = spaces[i] - 1;\n            actionIdx += numNonIdleActions;\n        }\n\n        envs[envIdx]->setAction(agentIdx, Action(actionMask));\n    }\n\n    void step()\n    {\n        vectorEnv->step();\n    }\n\n    bool isDone(int envIdx)\n    {\n        return vectorEnv->done[envIdx];\n    }\n\n    std::vector<float> getLastRewards()\n    {\n        int i = 0;\n\n        for (int envIdx = 0; envIdx < numEnvs; ++envIdx)\n            for (int agentIdx = 0; agentIdx < numAgentsPerEnv; ++agentIdx)\n                rewards[i++] = envs[envIdx]->getLastReward(agentIdx);\n\n        return rewards;\n    }\n\n    py::array_t<uint8_t> getObservation(int envIdx, int agentIdx)\n    {\n        const uint8_t *obsData = renderer->getObservation(envIdx, agentIdx);\n        return py::array_t<uint8_t>({h, w, 4}, obsData, py::none{});  // numpy object does not own memory\n    }\n\n    /**\n     * Call this before the first call to render()\n     */\n    void setRenderResolution(int hiresW, int hiresH)\n    {\n        renderW = hiresW;\n        renderH = hiresH;\n    }\n\n    void drawHires()\n    {\n        if (!hiresRenderer) {\n            if (useVulkan)\n#ifdef CORRADE_TARGET_APPLE\n                TLOG(ERROR) << \"Vulkan not supported on MacOS\";\n#else\n                hiresRenderer = std::make_unique<V4REnvRenderer>(envs, renderW, renderH, dynamic_cast<V4REnvRenderer *>(renderer.get()), true);\n#endif\n            else\n                hiresRenderer = std::make_unique<MagnumEnvRenderer>(envs, renderW, renderH);\n\n            for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx)\n                hiresRenderer->reset(*envs[envIdx], envIdx);\n        }\n\n        for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx) {\n            if (isDone(envIdx))\n                hiresRenderer->reset(*envs[envIdx], envIdx);\n\n            hiresRenderer->preDraw(*envs[envIdx], envIdx);\n        }\n\n        hiresRenderer->draw(envs);\n    }\n\n    void drawOverview()\n    {\n#ifdef WITH_GUI\n        if (!viewer && Viewer::viewerExists) {\n            TLOG(INFO) << \"Only one viewer per process is supported\";\n            return;\n        }\n\n        if (!viewer) {\n            static int argc = 1;\n            static const char *argv[] = {\"Overview\"};\n            Magnum::Platform::Application::Arguments fakeArgs{argc, (char **) argv};\n            TLOG(INFO) << __FUNCTION__ << \" Creating a viewer object\";\n            viewer = std::make_unique<Viewer>(envs, useVulkan, renderer.get(), fakeArgs);\n        }\n\n        viewer->step(vectorEnv->done);\n        viewer->mainLoopIteration();  // handle events, update the window, that kind of thing\n#else\n        // TLOG(ERROR) << \"Megaverse was built without GUI support\";\n#endif\n    }\n\n    py::array_t<uint8_t> getHiresObservation(int envIdx, int agentIdx)\n    {\n        const uint8_t *obsData = hiresRenderer->getObservation(envIdx, agentIdx);\n        return py::array_t<uint8_t>({renderH, renderW, 4}, obsData, py::none{});  // numpy object does not own memory\n    }\n\n    float trueObjective(int envIdx, int agentIdx) const\n    {\n        return vectorEnv->trueObjectives[envIdx][agentIdx];\n    }\n\n    std::map<std::string, float> getRewardShaping(int envIdx, int agentIdx)\n    {\n        return envs[envIdx]->getScenario().getRewardShaping(agentIdx);\n    }\n\n    void setRewardShaping(int envIdx, int agentIdx, const std::map<std::string, float> &rewardShaping)\n    {\n        envs[envIdx]->getScenario().setRewardShaping(agentIdx, rewardShaping);\n    }\n\n    /**\n     * Explicitly destroy the env and the renderer to avoid doing this when the Python object goes out-of-scope.\n     */\n    void close()\n    {\n        if (vectorEnv)\n            vectorEnv->close();\n\n#ifdef WITH_GUI\n        if (viewer)\n            viewer->exit(0);\n        viewer.reset();\n#endif\n\n        hiresRenderer.reset();\n        renderer.reset();\n        vectorEnv.reset();\n\n        envs.clear();\n    }\n\nprivate:\n    Envs envs;\n    int numEnvs, numAgentsPerEnv;\n    std::vector<float> rewards;  // to avoid reallocating on every call\n\n    std::unique_ptr<VectorEnv> vectorEnv;\n    std::unique_ptr<EnvRenderer> renderer, hiresRenderer;\n\n    Rng rng{std::random_device{}()};\n\n#ifdef WITH_GUI\n    std::unique_ptr<Viewer> viewer;\n#endif\n\n    bool useVulkan;\n    int w, h;\n    int renderW = 768, renderH = 432;\n\n    int numSimulationThreads;\n};\n\n\nPYBIND11_MODULE(megaverse, m)\n{\n    m.doc() = \"Megaverse Python bindings\"; // optional module docstring\n\n    m.def(\"set_megaverse_log_level\", &setMegaverseLogLevel, \"Megaverse Log Level (0 to disable all logs, 2 for warnings\");\n\n    py::class_<MegaverseGym>(m, \"MegaverseGym\")\n        .def(py::init<const std::string &, int, int, int, int, int, bool, const FloatParams &>())\n        .def(\"num_agents\", &MegaverseGym::numAgents)\n        .def(\"action_space_sizes\", &MegaverseGym::actionSpaceSizes)\n        .def(\"seed\", &MegaverseGym::seed)\n        .def(\"reset\", &MegaverseGym::reset)\n        .def(\"set_actions\", &MegaverseGym::setActions)\n        .def(\"step\", &MegaverseGym::step)\n        .def(\"is_done\", &MegaverseGym::isDone)\n        .def(\"get_observation\", &MegaverseGym::getObservation)\n        .def(\"get_last_rewards\", &MegaverseGym::getLastRewards)\n        .def(\"true_objective\", &MegaverseGym::trueObjective)\n        .def(\"set_render_resolution\", &MegaverseGym::setRenderResolution)\n        .def(\"draw_hires\", &MegaverseGym::drawHires)\n        .def(\"draw_overview\", &MegaverseGym::drawOverview)\n        .def(\"get_hires_observation\", &MegaverseGym::getHiresObservation)\n        .def(\"get_reward_shaping\", &MegaverseGym::getRewardShaping)\n        .def(\"set_reward_shaping\", &MegaverseGym::setRewardShaping)\n        .def(\"close\", &MegaverseGym::close);\n}\n"
  },
  {
    "path": "src/libs/env/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(libenv VERSION 0.1 LANGUAGES CXX)\n\nset(MAGNUM_DEPENDENCIES\n        Corrade::Main\n        Magnum::GL\n        Magnum::Magnum\n        Magnum::SceneGraph\n        MagnumIntegration::Bullet\n)\n\nadd_library_default(env)\ntarget_link_libraries(env PUBLIC util ${MAGNUM_DEPENDENCIES})\n"
  },
  {
    "path": "src/libs/env/include/env/agent.hpp",
    "content": "#pragma once\n\n#include <memory>\n\n#include <BulletCollision/CollisionDispatch/btGhostObject.h>\n\n#include <Magnum/SceneGraph/SceneGraph.h>\n\n#include <util/magnum.hpp>\n#include <util/voxel_grid.hpp>\n\n#include <env/physics.hpp>\n#include <env/voxel_state.hpp>\n#include <env/kinematic_character_controller.hpp>\n\n\nnamespace Megaverse\n{\n\nclass AbstractAgent : public Object3D\n{\npublic:\n    explicit AbstractAgent(Object3D *parent, btDynamicsWorld &bWorld, float verticalLookLimitRad);\n\n    virtual void updateTransform() = 0;\n\n    virtual void lookLeft(float dt) = 0;\n\n    virtual void lookRight(float dt) = 0;\n\n    virtual void lookUp(float dt) = 0;\n\n    virtual void lookDown(float dt) = 0;\n\n    virtual btVector3 forwardDirection() const = 0;\n\n    virtual btVector3 strafeLeftDirection() const = 0;\n\n    virtual bool onGround() const = 0;\n\n    virtual void accelerate(const btVector3 &acc, btScalar frameDuration) = 0;\n\n    virtual void jump() = 0;\n\n    virtual void teleport(const btVector3 &position) = 0;\n\n    virtual float getAgentHeight() = 0;\n\n    virtual Magnum::SceneGraph::Camera3D * getCamera() = 0;\n\n    virtual Object3D * getCameraObject() = 0;\n\n    virtual Object3D * interactLocation() = 0;\n\nprivate:\n    virtual void rotateYAxis(float radians) = 0;\n\nprotected:\n    float verticalLookLimitRad = 0.0f;\n\n    btDynamicsWorld &bWorld;\n};\n\n\nclass DefaultKinematicAgent : public AbstractAgent\n{\npublic:\n    explicit DefaultKinematicAgent(\n        Object3D *parent, btDynamicsWorld &bWorld, const Magnum::Vector3 &startingPosition,\n        float rotationRad, float verticalLookLimitRad\n    );\n\n    ~DefaultKinematicAgent() override;\n\n    void updateTransform() override;\n\n    void lookLeft(float dt) override;\n\n    void lookRight(float dt) override;\n\n    void lookUp(float dt) override;\n\n    void lookDown(float dt) override;\n\n    btVector3 forwardDirection() const override;\n\n    btVector3 strafeLeftDirection() const override;\n\n    bool onGround() const override;\n\n    void accelerate(const btVector3 &acc, btScalar frameDuration) override;\n\n    void jump() override;\n\n    void teleport(const btVector3 &position) override;\n\n    float getAgentHeight() override { return agentHeight; }\n\n    Magnum::SceneGraph::Camera3D * getCamera() override { return camera; }\n\n    Object3D * getCameraObject() override { return cameraObject; }\n\n    Object3D * interactLocation() override { return pickupSpot; }\n\nprivate:\n    void rotateYAxis(float radians) override;\n\nprivate:\n    static constexpr auto rotateRadians = 3.5f, rotateXRadians = 1.5f;\n    static constexpr auto agentHeight = 1.75f;\n\n    float currXRotation = 0.0f;\n\n    Object3D *cameraObject;\n    Magnum::SceneGraph::Camera3D *camera;\n    Object3D *pickupSpot;\n\n    std::unique_ptr<btCapsuleShape> capsuleShape;\n    btPairCachingGhostObject ghostObject;\n    std::unique_ptr<KinematicCharacterController> bCharacter;\n};\n\n}"
  },
  {
    "path": "src/libs/env/include/env/const.hpp",
    "content": "#pragma once\n\n#include <util/util.hpp>\n#include <util/magnum.hpp>\n\n\nnamespace Megaverse\n{\n\nusing ConstStr = const char *const;\n\nnamespace Str\n{\n    ConstStr teamSpirit = \"teamSpirit\";\n\n    ConstStr episodeLengthSec = \"episodeLengthSec\",\n             verticalLookLimitRad = \"verticalLookLimitRad\",\n             useUIRewardIndicators = \"useUIRewardIndicators\";\n}\n\n\n/**\n * Enum with default colors\n */\nenum class ColorRgb\n{\n    YELLOW = 0xffdd3c,\n    GREEN = 0x3bb372,\n    LIGHT_GREEN = 0x50c878,\n    BLUE = 0x2eb5d0,\n    LIGHT_BLUE = 0xadd8e6,\n    DARK_BLUE = 0x3a7fa6,\n    DARK_NAVY = 0x2c3e50,\n    ORANGE = 0xffb400,\n    GREY = 0xb3b3b3,\n    DARK_GREY = 0x555555,\n    VERY_DARK_GREY = 0x222222,\n    WHITE = 0xffffff,\n    RED = 0xff0000,\n    LIGHT_ORANGE = 0xffa770,\n    VIOLET = 0xd468ee,\n    LIGHT_PINK = 0xffe6e6,\n\n    VERY_LIGHT_YELLOW = 0xffffe6,\n    VERY_LIGHT_GREEN = 0xccffcc,\n    VERY_LIGHT_BLUE = 0xe6ecff,\n    VERY_LIGHT_GREY = 0xd9d9d9,\n    VERY_LIGHT_VIOLET = 0xf2e6ff,\n    VERY_LIGHT_ORANGE = 0xffebcc,\n\n    LAYOUT_DEFAULT = WHITE,\n    AGENT_EYES = DARK_NAVY,\n    MOVABLE_BOX = LIGHT_BLUE,\n    EXIT_PAD = LIGHT_GREEN,\n    BUILDING_ZONE = DARK_GREY,\n};\n\nconst ColorRgb allColors[] = {\n    ColorRgb::YELLOW,\n    ColorRgb::GREEN,\n    ColorRgb::LIGHT_GREEN,\n    ColorRgb::BLUE,\n    ColorRgb::LIGHT_BLUE,\n    ColorRgb::DARK_BLUE,\n    ColorRgb::DARK_NAVY,\n    ColorRgb::ORANGE,\n    ColorRgb::GREY,\n    ColorRgb::DARK_GREY,\n    ColorRgb::VERY_DARK_GREY,\n    ColorRgb::WHITE,\n    ColorRgb::RED,\n    ColorRgb::LIGHT_ORANGE,\n    ColorRgb::VIOLET,\n    ColorRgb::LIGHT_PINK,\n\n    ColorRgb::VERY_LIGHT_YELLOW,\n    ColorRgb::VERY_LIGHT_GREEN,\n    ColorRgb::VERY_LIGHT_BLUE,\n    ColorRgb::VERY_LIGHT_GREY,\n    ColorRgb::VERY_LIGHT_VIOLET,\n    ColorRgb::VERY_LIGHT_ORANGE,\n};\nconst int numColors = ARR_LENGTH(allColors);\n\nconst ColorRgb agentColors[] = {ColorRgb::YELLOW, ColorRgb::GREEN, ColorRgb::BLUE, ColorRgb::ORANGE, ColorRgb::VIOLET, ColorRgb::VERY_DARK_GREY, ColorRgb::RED};\nconst int numAgentColors = ARR_LENGTH(agentColors);\n\ninline Magnum::Color3 rgb(ColorRgb color) { return toRgbf((unsigned long long)color); }\n\ninline ColorRgb sampleRandomColor(Rng &rng)\n{\n    const auto idx = randRange(0, numColors, rng);\n    return allColors[idx];\n}\n\nconst ColorRgb objectColors[] = {\n    ColorRgb::YELLOW,\n    ColorRgb::GREEN,\n    ColorRgb::LIGHT_GREEN,\n    ColorRgb::BLUE,\n    ColorRgb::LIGHT_BLUE,\n    ColorRgb::DARK_BLUE,\n    ColorRgb::ORANGE,\n    ColorRgb::GREY,\n    ColorRgb::DARK_GREY,\n    ColorRgb::WHITE,\n    ColorRgb::RED,\n    ColorRgb::LIGHT_ORANGE,\n    ColorRgb::VIOLET,\n    ColorRgb::LIGHT_PINK,\n};\n\nconst int numObjectColors = ARR_LENGTH(objectColors);\n\ninline ColorRgb randomObjectColor(Rng &rng)\n{\n    const auto idx = randRange(0, numObjectColors, rng);\n    return objectColors[idx];\n}\n\nconst ColorRgb layoutColors[] = {\n    ColorRgb::LAYOUT_DEFAULT,\n    ColorRgb::VERY_LIGHT_YELLOW,\n    ColorRgb::VERY_LIGHT_GREEN,\n    ColorRgb::VERY_LIGHT_BLUE,\n    ColorRgb::VERY_LIGHT_GREY,\n    ColorRgb::VERY_LIGHT_ORANGE,\n    ColorRgb::GREY,\n    ColorRgb::GREY,\n    ColorRgb::GREY,\n    ColorRgb::GREY,\n    ColorRgb::DARK_GREY,\n    ColorRgb::DARK_GREY,\n    ColorRgb::DARK_GREY,\n    ColorRgb::DARK_GREY,\n};\nconst int numLayoutColors = ARR_LENGTH(layoutColors);\n\ninline ColorRgb randomLayoutColor(Rng &rng)\n{\n    const auto idx = randRange(0, numLayoutColors, rng);\n    return layoutColors[idx];\n}\n\n}\n"
  },
  {
    "path": "src/libs/env/include/env/env.hpp",
    "content": "#pragma once\n\n#include <map>\n#include <random>\n#include <vector>\n#include <algorithm>\n\n#include <Magnum/SceneGraph/Scene.h>\n#include <Magnum/SceneGraph/SceneGraph.h>\n\n#include <util/util.hpp>\n\n#include <env/agent.hpp>\n#include <env/physics.hpp>\n\n\nnamespace Megaverse\n{\n\nclass Scenario;\n\nenum class Action\n{\n    Idle = 0,\n\n    Left = 1 << 1,\n    Right = 1 << 2,\n\n    Forward = 1 << 3,\n    Backward = 1 << 4,\n\n    LookLeft = 1 << 5,\n    LookRight = 1 << 6,\n\n    Jump = 1 << 7,\n    Interact = 1 << 8,\n\n    LookDown = 1 << 9,\n    LookUp = 1 << 10,\n\n    NumActions = 11,\n};\n\n\ninline Action operator|(Action a, Action b) { return Action(int(a) | int(b)); }\n\ninline Action &operator|=(Action &a, Action b) { return (Action &) ((int &) a |= int(b)); }\n\ninline Action operator&(Action a, Action b) { return Action(int(a) & int(b)); }\n\ninline Action &operator&=(Action &a, Action b) { return (Action &) ((int &) a &= int(b)); }\n\ninline Action operator~(Action a) { return Action(~int(a)); }\n\ninline bool operator!(Action a) { return a == Action::Idle; }\n\n\nenum class DrawableType\n{\n    First = 0,\n\n    Box = 0,\n    Capsule = 1,\n    Sphere = 2,\n    Cone = 3,\n    Cylinder = 4,\n\n    NumTypes,\n};\n\n\nstruct SceneObjectInfo\n{\n    SceneObjectInfo(Object3D *objectPtr, const Magnum::Color3 &color)\n        : objectPtr{objectPtr}\n          , color{color}\n    {\n    }\n\n    Object3D *objectPtr;\n    Magnum::Color3 color;\n};\n\n\nusing FloatParams = std::map<std::string, float>;\nusing Agents = std::vector<AbstractAgent *>;\nusing DrawablesMap = std::map<DrawableType, std::vector<SceneObjectInfo>>;\nusing RewardShaping = std::map<std::string, float>;\n\nclass Env\n{\npublic:\n    /**\n     * Physics-related fields (Bullet physics engine)\n     */\n    struct EnvPhysics\n    {\n        EnvPhysics()\n        {\n            // what does this really do?\n            bBroadphase.getOverlappingPairCache()->setInternalGhostPairCallback(&ghostPairCallback);\n        }\n\n        ~EnvPhysics()\n        {\n            collisionShapes.clear();\n        }\n\n        btGhostPairCallback ghostPairCallback;\n\n        btDbvtBroadphase bBroadphase;\n        btSequentialImpulseConstraintSolver bConstraintSolver;\n        btDefaultCollisionConfiguration bCollisionConfiguration;\n        btCollisionDispatcher bCollisionDispatcher{&bCollisionConfiguration};\n        btDiscreteDynamicsWorld bWorld{&bCollisionDispatcher, &bBroadphase, &bConstraintSolver, &bCollisionConfiguration};\n\n        std::vector<std::unique_ptr<btCollisionShape>> collisionShapes;\n    };\n\n    /**\n     * Current state of the environment.\n     * This is what other components (e.g. Scenario) will get access to.\n     */\n    struct EnvState\n    {\n    public:\n        explicit EnvState(int numAgents)\n        : physics{std::make_unique<EnvPhysics>()}\n        , currAction(size_t(numAgents), Action::Idle)\n        , lastReward(size_t(numAgents), 0)\n        , totalReward(size_t(numAgents), 0.0f)\n        {\n        }\n\n        void reset()\n        {\n            done = false;\n            currEpisodeSec = 0;\n            numFrames = 0;\n\n            std::fill(currAction.begin(), currAction.end(), Action::Idle);\n            std::fill(lastReward.begin(), lastReward.end(), 0.0f);\n            std::fill(totalReward.begin(), totalReward.end(), 0.0f);\n\n            scene = std::make_unique<Scene3D>();\n\n            agents.clear();\n\n            // completely reset the whole simulation\n            physics = std::make_unique<EnvPhysics>();\n        }\n\n    public:\n        std::unique_ptr<EnvPhysics> physics;\n\n        // Basic environment info\n        bool done = false;\n        int numFrames = 0;\n        float currEpisodeSec = 0;\n        float simulationStepSeconds = 1.0f / 15.0f;  // 15 FPS is default\n        float lastFrameDurationSec = simulationStepSeconds;\n        std::vector<Action> currAction;\n        std::vector<float> lastReward, totalReward;\n\n        std::unique_ptr<Scene3D> scene;\n\n        Agents agents;\n\n        Rng rng{std::random_device{}()};\n    };\n\npublic:\n    explicit Env(const std::string &scenarioName, int numAgents = 2, const FloatParams& customFloatParams = FloatParams{});\n\n    ~Env();\n\n    int getNumAgents() const { return numAgents; }\n\n    Scenario & getScenario() { return *scenario; }\n\n    Scene3D & getScene() const { return *state.scene; }\n\n    Agents & getAgents() { return state.agents; }\n\n    EnvPhysics & getPhysics() const { return *state.physics; }\n\n    /**\n     * Main interface between the env and the renderer.\n     * @return the list of drawables for each geometric shape supported.\n     */\n    const DrawablesMap & getDrawables() const { return drawables; }\n\n    void reset();\n\n    /**\n     * Set action for the next tick.\n     * @param agentIdx index of the agent for which we're setting the action\n     * @param action action mask (see enum)\n     */\n    void setAction(int agentIdx, Action action);\n\n    /**\n     * Advance simulation by one step.\n     */\n    void step();\n\n    bool isDone() const { return state.done; }\n\n    /**\n     * @param agentIdx agent for which to query the last reward\n     * @return reward in the last tick\n     */\n    float getLastReward(int agentIdx) const { return state.lastReward[agentIdx]; }\n\n    float getTotalReward(int agentIdx) const { return state.totalReward[agentIdx]; }\n\n    /**\n     * Unshaped reward that we're actually trying to maximize.\n     */\n    float trueObjective(int agentIdx) const;\n\n    float episodeLengthSec() const;\n\n    float remainingTimeFraction() const\n    {\n        const auto len = episodeLengthSec();\n        return std::max(0.0f, (len - state.currEpisodeSec) / len);\n    }\n\n    void terminateEpisodeOnNextFrame();\n\n    /**\n     * We need this because of the requirements of the Vulkan renderer (materials have to be known in advance)\n     */\n    std::vector<Magnum::Color3> getPalette() const;\n\n    /**\n     * Seed the rng with specific seed value.\n     */\n    void seed(int seedValue);\n\n    Rng &getRng() { return state.rng; }\n\n    /**\n     * This is when we're running an actual realtime rendering loop with human controls.\n     * Should not be used by Gym env interface.\n     * @param sec actual duration of the last frame.\n     */\n    void setFrameDuration(float sec) { state.lastFrameDurationSec = sec; }\n\n    void setSimulationResolution(float sec) { state.simulationStepSeconds = sec; }\n\npublic:\n    // need better mechanism for this\n    static const std::vector<int> actionSpaceSizes;\n\nprivate:\n    std::string scenarioName;\n    std::unique_ptr<Scenario> scenario;\n\n    EnvState state;\n    int numAgents;\n    DrawablesMap drawables;\n};\n\n\nusing Envs = std::vector<std::unique_ptr<Env>>;\n\n}"
  },
  {
    "path": "src/libs/env/include/env/env_renderer.hpp",
    "content": "#pragma once\n\n#include <env/env.hpp>\n\n\nnamespace Megaverse\n{\n\n// defined later in render_utils.cpp\nclass Overview;\n\nclass EnvRenderer\n{\npublic:\n    virtual ~EnvRenderer() = default;\n\n    virtual void reset(Env &env, int envIdx) = 0;\n\n    virtual void preDraw(Env &env, int envIndex) = 0;\n\n    virtual void draw(Envs &envs) = 0;\n\n    /**\n     * Query the pointer to memory holding the latest observation for an agent in an env.\n     * @param envIdx env index.\n     * @param agentIdx agent for which we're querying the observation.\n     * @return pointer to the memory holding the observation.\n     */\n    virtual const uint8_t *getObservation(int envIdx, int agentIdx) const = 0;\n\n    virtual Overview * getOverview() = 0;\n};\n\ninline std::tuple<float, float, float, float> agentCameraParameters()\n{\n    float fov = 100, near = 0.01, far = 120.0, aspectRatio = 128.0f / 72.0f;\n    return std::make_tuple(fov, near, far, aspectRatio);\n}\n\ninline std::tuple<float, float, float, float> overviewCameraParameters()\n{\n    auto [fov, near, far, aspectRatio] = agentCameraParameters();\n    fov = 100, near = 0.1, far = 600.0;\n\n    return std::make_tuple(fov, near, far, aspectRatio);\n}\n\n}"
  },
  {
    "path": "src/libs/env/include/env/kinematic_character_controller.hpp",
    "content": "#pragma once\n\n#include \"LinearMath/btVector3.h\"\n\n#include \"BulletDynamics/Dynamics/btActionInterface.h\"\n#include \"BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h\"\n\nclass btCollisionShape;\nclass btConvexShape;\nclass btRigidBody;\nclass btCollisionWorld;\nclass btCollisionDispatcher;\nclass btPairCachingGhostObject;\n\n\nnamespace Megaverse\n{\n\n///btKinematicCharacterController is an object that supports a sliding motion in a world.\n///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations.\n///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user.\nATTRIBUTE_ALIGNED16(class)\nKinematicCharacterController : public btActionInterface\n{\npublic:\n    BT_DECLARE_ALIGNED_ALLOCATOR();\n\n    KinematicCharacterController(btPairCachingGhostObject *ghostObject, btConvexShape *convexShape, btScalar stepHeight,\n                                 const btVector3 &up = btVector3(1.0, 0.0, 0.0));\n\n    ~KinematicCharacterController() override;\n\n    ///btActionInterface interface\n    void updateAction(btCollisionWorld *collisionWorld, btScalar deltaTime) override\n    {\n        preStep(collisionWorld);\n        playerStep(collisionWorld, deltaTime);\n    }\n\n    ///btActionInterface interface\n    void debugDraw(btIDebugDraw *debugDrawer) override;\n\n    void setUp(const btVector3 &up);\n\n    const btVector3 &getUp() { return m_up; }\n\n    /// This should probably be called setPositionIncrementPerSimulatorStep.\n    /// This is neither a direction nor a velocity, but the amount to\n    ///\tincrement the position each simulation iteration, regardless\n    ///\tof dt.\n    /// This call will reset any velocity set by setVelocityForTimeInterval().\n    virtual void setWalkDirection(const btVector3 &walkDirection);\n\n    virtual void setAngularVelocity(const btVector3 &velocity);\n\n    virtual const btVector3 &getAngularVelocity() const;\n\n    virtual void setLinearVelocity(const btVector3 &velocity);\n\n    virtual btVector3 getLinearVelocity() const;\n\n    void setAngularDamping(btScalar d)\n    {\n        m_angularDamping = btClamped(d, (btScalar) btScalar(0.0), (btScalar) btScalar(1.0));\n    }\n\n    btScalar getAngularDamping() const { return m_angularDamping; }\n\n    void reset(btCollisionWorld *collisionWorld);\n\n    void warp(const btVector3 &origin);\n\n    void preStep(btCollisionWorld *collisionWorld);\n\n    void playerStep(btCollisionWorld *collisionWorld, btScalar dt);\n\n    void setStepHeight(btScalar h);\n\n    btScalar getStepHeight() const { return m_stepHeight; }\n\n    void setFallSpeed(btScalar fallSpeed);\n\n    btScalar getFallSpeed() const { return m_fallSpeed; }\n\n    void setJumpSpeed(btScalar jumpSpeed);\n\n    btScalar getJumpSpeed() const { return m_jumpSpeed; }\n\n    void setMaxJumpHeight(btScalar maxJumpHeight);\n\n    bool canJump() const;\n\n    void jump(const btVector3 &v = btVector3(0, 0, 0));\n\n    void applyImpulse(const btVector3 &v) { jump(v); }\n\n    void setGravity(const btVector3 &gravity);\n\n    btVector3 getGravity() const;\n\n    /// The max slope determines the maximum angle that the controller can walk up.\n    /// The slope angle is measured in radians.\n    void setMaxSlope(btScalar slopeRadians);\n\n    btScalar getMaxSlope() const;\n\n    void setMaxPenetrationDepth(btScalar d);\n\n    btScalar getMaxPenetrationDepth() const;\n\n    btPairCachingGhostObject *getGhostObject();\n\n    void setUseGhostSweepTest(bool useGhostObjectSweepTest)\n    {\n        m_useGhostObjectSweepTest = useGhostObjectSweepTest;\n    }\n\n    bool onGround() const;\n\n    void setUpInterpolate(bool value);\n\n    void setAcceleration(btVector3 acc, btScalar dt);\n\nprotected:\n    static btVector3 *getUpAxisDirections();\n\n    btVector3 computeReflectionDirection(const btVector3 &direction, const btVector3 &normal);\n\n    btVector3 parallelComponent(const btVector3 &direction, const btVector3 &normal);\n\n    btVector3 perpindicularComponent(const btVector3 &direction, const btVector3 &normal);\n\n    bool recoverFromPenetration(btCollisionWorld *collisionWorld, int iteration);\n\n    void stepUp(btCollisionWorld *collisionWorld);\n\n    void updateTargetPositionBasedOnCollision(const btVector3 &hit_normal, btScalar closestHitFraction);\n\n    void stepForwardAndStrafe(btCollisionWorld *collisionWorld, const btVector3 &horizontalVelocity, btScalar dt);\n\n    void stepDown(btCollisionWorld *collisionWorld, btScalar dt);\n\n    virtual bool needsCollision(const btCollisionObject *body0, const btCollisionObject *body1);\n\n    void setUpVector(const btVector3 &up);\n\n    btQuaternion getRotation(btVector3 &v0, btVector3 &v1) const;\n\nprotected:\n    btScalar m_halfHeight;\n\n    btPairCachingGhostObject *m_ghostObject;\n    btConvexShape *m_convexShape;  //is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast\n\n    btScalar m_maxPenetrationDepth = 0.041f;\n    btScalar m_verticalVelocity;\n    btScalar m_verticalOffset;\n    btScalar m_fallSpeed;\n    btScalar m_jumpSpeed;\n    btScalar m_SetjumpSpeed;\n    btScalar m_maxJumpHeight;\n    btScalar m_maxSlopeRadians;  // Slope angle that is set (used for returning the exact value)\n    btScalar m_maxSlopeCosine;   // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization)\n\n    btScalar m_turnAngle;\n\n    btScalar m_stepHeight;\n\n    btScalar m_gravity = 1.4f * 9.8f;\n\n    btVector3 horizontalVelocity;\n\n    btScalar maxHorizontalSpeed = 4.5f;  // max walking speed, can be exceeded through other events (explosion, impulse)\n    btScalar maxAirSpeed = 1.0f;\n    btScalar normalDeceleration = 15.0f;\n    btScalar maxAcceleration = 35.0f + normalDeceleration, maxAirAcceleration = 3.0f;\n    btScalar exceedingSpeedLimitDeceleration = maxAcceleration * 2;\n\n    btVector3 m_AngVel;\n\n    btVector3 m_jumpPosition;\n\n    //some internal variables\n    btVector3 m_currentPosition;\n    btScalar m_currentStepOffset;\n    btVector3 m_targetPosition;\n\n    btQuaternion m_currentOrientation;\n    btQuaternion m_targetOrientation;\n\n    ///keep track of the contact manifolds\n    btManifoldArray m_manifoldArray;\n\n    bool m_touchingContact;\n    btVector3 m_touchingNormal;\n\n    btScalar m_angularDamping;\n\n    bool m_wasOnGround;\n    bool m_wasJumping;\n    bool m_useGhostObjectSweepTest;\n    btVector3 m_up;\n    btVector3 m_jumpAxis;\n\n    bool m_interpolateUp;\n};\n\n}"
  },
  {
    "path": "src/libs/env/include/env/physics.hpp",
    "content": "#pragma once\n\n#include <btBulletDynamicsCommon.h>\n\n#include <Corrade/Containers/Pointer.h>\n\n#include <Magnum/BulletIntegration/Integration.h>\n#include <Magnum/BulletIntegration/MotionState.h>\n#include <Magnum/SceneGraph/TranslationRotationScalingTransformation3D.h>\n\n#include <util/magnum.hpp>\n\n#include <util/tiny_logger.hpp>\n\n\nnamespace Megaverse\n{\n\nclass RigidBody : public Object3D\n{\npublic:\n    RigidBody(Object3D *parent, Magnum::Float mass, btCollisionShape *bShape, btDynamicsWorld &bWorld)\n        : Object3D{parent}, bWorld{bWorld}\n    {\n        // calculate inertia so the object reacts as it should with rotation and everything\n        btVector3 bInertia(0.0f, 0.0f, 0.0f);\n        if (!Magnum::Math::TypeTraits<Magnum::Float>::equals(mass, 0.0f))\n            bShape->calculateLocalInertia(mass, bInertia);\n\n        // bullet rigid body setup\n        motionState = std::make_unique<Magnum::BulletIntegration::MotionState>(*this);\n        bRigidBody = std::make_unique<btRigidBody>(btRigidBody::btRigidBodyConstructionInfo{mass, &motionState->btMotionState(), bShape, bInertia});\n\n        bRigidBody->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);\n\n        // bRigidBody->forceActivationState(DISABLE_DEACTIVATION);  // do we need this?\n        bWorld.addRigidBody(bRigidBody.get());\n    }\n\n    ~RigidBody() override\n    {\n        // similar to Bullet demos, delete motion state first, then remove rigid body from the world, and then delete the rigid body\n        motionState.reset();\n        bWorld.removeRigidBody(bRigidBody.get());\n        bRigidBody.reset();\n    }\n\n    btRigidBody &rigidBody() { return *bRigidBody; }\n\n    bool colliding() const\n    {\n        return !(bRigidBody->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE);\n    }\n\n    /**\n     * Allows to set collsion shape scale relative to the object scale\n     */\n    void setCollisionScale(const Magnum::Vector3 &scale)\n    {\n        collisionScale = scale;\n    }\n\n    void setCollisionOffset(const Magnum::Vector3 &offset)\n    {\n        collisionOffset = offset;\n    }\n\n    /* needed after changing the pose from Magnum side */\n    void syncPose()\n    {\n        const auto &m = absoluteTransformationMatrix();\n        bRigidBody->setWorldTransform(btTransform{btMatrix3x3{m.rotation()}, btVector3{m.translation() + collisionOffset}});\n        bRigidBody->getCollisionShape()->setLocalScaling(btVector3{m.scaling() * collisionScale});\n    }\n\n    void toggleCollision()\n    {\n        const auto flags = bRigidBody->getCollisionFlags();\n        if (flags & btCollisionObject::CF_NO_CONTACT_RESPONSE) {\n            // no collisions for this object, enabling collisions...\n            bRigidBody->setCollisionFlags(flags & ~btCollisionObject::CF_NO_CONTACT_RESPONSE);\n        } else {\n            bRigidBody->setCollisionFlags(flags | btCollisionObject::CF_NO_CONTACT_RESPONSE);\n        }\n    }\n\nprivate:\n    btDynamicsWorld &bWorld;\n    std::unique_ptr<btRigidBody> bRigidBody;\n    std::unique_ptr<Magnum::BulletIntegration::MotionState> motionState;\n    Magnum::Vector3 collisionScale{1, 1, 1};\n    Magnum::Vector3 collisionOffset;\n};\n\n}"
  },
  {
    "path": "src/libs/env/include/env/scenario.hpp",
    "content": "#pragma once\n\n#include <map>\n#include <memory>\n#include <string>\n\n#include <util/tiny_logger.hpp>\n#include <util/string_utils.hpp>\n\n#include <env/env.hpp>\n#include <env/const.hpp>\n\n\nnamespace Megaverse\n{\n\nclass ScenarioComponent;\n\nclass Scenario\n{\n    friend class ScenarioComponent;\n\npublic:\n    using ScenarioPtr = std::unique_ptr<Scenario>;\n    using FactoryFunc = ScenarioPtr (*)(const std::string &, Env &, Env::EnvState &);\n    using ScenarioRegistry = std::map<std::string, FactoryFunc>;\n\npublic:\n    explicit Scenario(std::string scenarioName, Env &env, Env::EnvState &envState)\n    : scenarioName{std::move(scenarioName)}\n    , env{env}\n    , envState{envState}\n    , rewardShaping(size_t(env.getNumAgents()))\n    {\n    }\n\n    virtual ~Scenario() = default;\n\n/**\n * Scenario registry and factory methods for instantiating custom scenarios.\n */\npublic:\n    static void registerScenario(const std::string &scenarioName, FactoryFunc factoryFunc)\n    {\n        auto &scenarioRegistry = getScenarioRegistry();\n        const auto scenarioNameLowercase = toLower(scenarioName);\n        scenarioRegistry[scenarioNameLowercase] = factoryFunc;\n        TLOG(INFO) << \"Scenario \" << scenarioNameLowercase << \" registered! \" << scenarioRegistry.size() << \" scenarios.\";\n    }\n\n    static std::vector<ScenarioRegistry::key_type> registeredScenarios()\n    {\n        auto &scenarioRegistry = getScenarioRegistry();\n        std::vector<ScenarioRegistry::key_type> keys;\n        keys.reserve(scenarioRegistry.size());\n        for (const auto& [key, _] : scenarioRegistry)\n            keys.emplace_back(key);\n        return keys;\n    }\n\n    static ScenarioPtr create(const std::string &scenarioName, Env &env, Env::EnvState &envState)\n    {\n        const auto scenarioNameLowercase = toLower(scenarioName);\n        const auto &scenarioRegistry = getScenarioRegistry();\n\n        // TLOG(INFO) << \"Num scenarios \" << scenarioRegistry.size();\n        // TLOG(INFO) << \"Registry ptr \" << &scenarioRegistry;\n        // for (const auto &[k,v]: scenarioRegistry)\n        //    TLOG(INFO) << k;\n\n        if (!scenarioRegistry.count(scenarioNameLowercase))\n            TLOG(FATAL) << \"Unknown scenario \" << scenarioNameLowercase << \". Did you register the scenario in scenariosGlobalInit()?\";\n\n        const auto factoryFunc = scenarioRegistry.at(scenarioNameLowercase);\n\n        return factoryFunc(scenarioNameLowercase, env, envState);\n    }\n\n    template<typename ScenarioType>\n    static std::unique_ptr<Scenario> scenarioFactory(const std::string &scenarioName, Env &env, Env::EnvState &envState)\n    {\n        ScenarioPtr p = std::make_unique<ScenarioType>(scenarioName, env, envState);\n        return p;\n    }\n\n/**\n * Interface between environment and scenario objects.\n */\npublic:\n    /**\n     * Called once after construction.\n     * We can't call virtual methods in the ctor, therefore this method can be useful.\n     */\n    virtual void init()\n    {\n        initializeDefaultParameters();\n\n        for (int i = 0; i < env.getNumAgents(); ++i)\n            rewardShaping[i] = {{Str::teamSpirit, 0.0f}};\n\n        // initialize default reward shaping specific for this scenario\n        initRewardShaping();\n    }\n\n    /**\n     * Called on the episode boundary.\n     */\n    virtual void reset() {}\n\n    /**\n     * Easy way to terminate the episode a bit more smoothly, rather than abruptly (i.e. on the same frame the last\n     * reward was collected).\n     */\n    void doneWithTimer(float remainingTimeSeconds=0.3f)\n    {\n        envState.currEpisodeSec = std::max(envState.currEpisodeSec, episodeLengthSec() - remainingTimeSeconds);\n    }\n\n    /**\n     * This is called by the environment before the physics simulation step.\n     */\n    virtual void preStep() {}\n\n    /**\n     * This is called by the environment after the physics simulation step.\n     * This method should normally contain main logic of the scenario.\n     */\n    virtual void step() {}\n\n    /**\n     * Called after every step() by the environment, use to adjust health bars, etc.\n     */\n    virtual void updateUI() {}\n\n    /**\n     * @return vector with starting positions of the agents.\n     */\n    virtual std::vector<Magnum::Vector3> agentStartingPositions() = 0;\n\n    /**\n     * Called by the env to generate the agent objects for the episode.\n     */\n    virtual void spawnAgents(std::vector<AbstractAgent *> &) = 0;\n\n    /**\n     * Called by the env to query the set of drawables for the episode.\n     */\n    virtual void addEpisodeDrawables(DrawablesMap &) {}\n\n    /**\n     * Same as above, but for drawables related to agents\n     */\n    virtual void addEpisodeAgentsDrawables(DrawablesMap &) {}\n\n    /**\n     * We display a rudimentary HUD just by drawing a bunch of geometric primitives very close to the camera.\n     */\n    virtual void addUIDrawables(DrawablesMap &) {}\n\n    /**\n     * @return a set of colors used by the renderer in this scenario.\n     */\n    virtual std::vector<Magnum::Color3> getPalette() const = 0;\n\n    /**\n     * @return unshaped reward for the current episode (i.e. 1 for success 0 for failure)\n     * Typically called only on the last frame of the episode, when done=True\n     */\n    virtual float trueObjective(int agentIdx) const = 0;\n\n    /**\n     * @return episode duration in seconds, this can be overridden\n     */\n    virtual float episodeLengthSec() const\n    {\n        const auto episodeLengthSec = getFloatParams().at(Str::episodeLengthSec);\n        return episodeLengthSec;\n    }\n\n    /**\n     * Each environment should provide the reward shaping dictionary which allows changing rewards through API\n     * (even during training)\n     */\n    virtual RewardShaping defaultRewardShaping() const = 0;\n\n    /**\n     * Utility function, used by initRewardShaping() implementations.\n     * Replaces rewards in rewardShaping with those provided by rs (or adds them to the map if they don't exist).\n     */\n    void initRewards(const RewardShaping &rs)\n    {\n        for (int i = 0; i < env.getNumAgents(); ++i)\n            for (const auto &[rewardName, value] : rs)\n                rewardShaping[i][rewardName] = value;\n    }\n\n    /**\n     * Initialize default reward shaping for this scenario. Should be overloaded by all scenarios.\n     */\n    virtual void initRewardShaping()\n    {\n        initRewards(defaultRewardShaping());\n    }\n\n    /**\n     * @param agentIdx\n     * @return current reward shaping for the agent\n     */\n    virtual RewardShaping & getRewardShaping(int agentIdx) { return rewardShaping[agentIdx]; }\n\n    /**\n     * @param agentIdx\n     * @param rs new reward shaping for the agent\n     */\n    virtual void setRewardShaping(int agentIdx, const RewardShaping &rs) { rewardShaping[agentIdx] = rs; }\n\n/**\n * Other utility functions.\n */\npublic:\n    /**\n     * Polymorphically initialize params, if derived scenarios have custom default parameters they should override\n     * this method.\n     */\n    virtual void initializeDefaultParameters()\n    {\n        auto &fp = floatParams;\n        fp[Str::episodeLengthSec] = 60.0f;\n        fp[Str::verticalLookLimitRad] = 0.2f;\n        fp[Str::useUIRewardIndicators] = 0.0f;\n    }\n\n    virtual const FloatParams & getFloatParams() const { return floatParams; }\n\n    /**\n     * This default behavior should typically be sufficient, although can also be overridden.\n     */\n    virtual void setCustomParameters(const FloatParams &customFloatParams)\n    {\n        for (const auto &[k, v] : customFloatParams)\n            floatParams[k] = v;\n    }\n\nprotected:\n    /**\n     * @return reward for a specific string key for a particular agent in the environment\n     * Since different agents can be controlled by different policies, they can also have different reward shaping\n     * associated with them (e.g. when we're doing PBT).\n     * Therefore we need a separate rewardShaping dictionary for every agent.\n     */\n    virtual float getReward(const std::string &rewardName, int agentIdx) const\n    {\n        return rewardShaping[agentIdx].at(rewardName);\n    }\n\n    /**\n     * Reward agent individually, do not reward other agents even if teamSpirit > 0\n     */\n    virtual void rewardAgent(const std::string &rewardName, int agentIdx, float multiplier)\n    {\n        envState.lastReward[agentIdx] += getReward(rewardName, agentIdx) * multiplier;\n    }\n\n    /**\n     * @return teamSpirit configured for this agent, can be used in collaborative tasks.\n     */\n    virtual float teamSpirit(int agentIdx) const\n    {\n        return getReward(Str::teamSpirit, agentIdx);\n    }\n\n    /**\n     * Which team the agent belongs to. By default all agents are on the same team.\n     */\n    virtual int teamAffinity(int /*agentIdx*/) const { return 0; }\n\n    virtual int teamSize(const int agentIdx) const {\n        const int currTeam = teamAffinity(agentIdx);\n        int size = 0;\n        for (int i = 0; i < env.getNumAgents(); ++i)\n            size += currTeam == teamAffinity(i) ? 1 : 0;\n\n        return size;\n    }\n\n    /**\n     * Reward all agents, taking teamSpirit into account. Can be useful for collaborative tasks.\n     * TeamSpirit is expected to be in [0, 1] range.\n     * The agent whose action was rewarded gets the full reward. Other agents get teamSpirit * reward.\n     */\n    virtual void rewardTeam(const std::string &rewardName, int agentIdx, float multiplier)\n    {\n        const auto currTeam = teamAffinity(agentIdx);\n        rewardAgent(rewardName, agentIdx, multiplier * (1 - teamSpirit(agentIdx)));\n        for (int i = 0; i < env.getNumAgents(); ++i)\n            if (teamAffinity(i) == currTeam)\n                envState.lastReward[i] += getReward(rewardName, i) * teamSpirit(i) * multiplier / teamSize(i);\n    }\n\n    /**\n     * Reward all agents equally, regardless of team spirit.\n     */\n    virtual void rewardAll(const std::string &rewardName, float multiplier)\n    {\n        for (int i = 0; i < env.getNumAgents(); ++i)\n            rewardAgent(rewardName, i, multiplier);\n    }\n\nprivate:\n    static ScenarioRegistry & getScenarioRegistry()\n    {\n        static ScenarioRegistry scenarioRegistry;\n        return scenarioRegistry;\n    }\n\nprotected:\n    std::string scenarioName;\n\n    // default values, can be overridden in ctor\n    FloatParams floatParams;\n\n    /**\n     * Adds an optional mechanism for components to access each other.\n     * Scenarios may decide to register or not to register their components here.\n     */\n    std::vector<ScenarioComponent *> components;\n\n    Env &env;\n    Env::EnvState &envState;\n\n    // reward shaping schemes for every agent in the env\n    std::vector<RewardShaping> rewardShaping;\n};\n\n}\n"
  },
  {
    "path": "src/libs/env/include/env/scenario_component.hpp",
    "content": "#pragma once\n\n#include <env/scenario.hpp>\n\n\nnamespace Megaverse\n{\n\n/**\n * We decompose behaviors in scenarios into reusable components which can be used in multiple scenarios.\n * This is a base class for all scenario components.\n */\nclass ScenarioComponent\n{\npublic:\n    explicit ScenarioComponent(Scenario &scenario)\n        : scenario{scenario}\n    {\n    }\n\n    virtual ~ScenarioComponent() = default;\n\npublic:\n    virtual void reset(Env &, Env::EnvState &) {}\n\n    virtual void step(Env &, Env::EnvState &) {}\n\nprotected:\n    /**\n     * When needed a component can access the parent scenario.\n     */\n    Scenario &scenario;\n};\n\n}"
  },
  {
    "path": "src/libs/env/include/env/vector_env.hpp",
    "content": "#pragma once\n\n#include <atomic>\n#include <thread>\n#include <condition_variable>\n\n#include <env/env.hpp>\n#include <env/env_renderer.hpp>\n\n\nnamespace Megaverse\n{\n\nclass VectorEnv\n{\npublic:\n    enum class Task\n    {\n        IDLE,\n        STEP,\n        RESET,\n        TERMINATE,\n    };\n\npublic:\n    explicit VectorEnv(Envs &envs, EnvRenderer &renderer, int numThreads);\n\n    void step();\n\n    void reset();\n\n    void close();\n\nprivate:\n    void taskFunc(Task task, int threadIdx);\n\n    void executeTask(Task task);\n\n    void stepEnv(int envIdx);\n\n    void resetEnv(int envIdx);\n\npublic:\n    std::vector<std::unique_ptr<Env>> &envs;\n    EnvRenderer &renderer;\n\n    std::vector<bool> done;\n    std::vector<std::vector<float>> trueObjectives;\n\nprivate:\n    int numThreads{}, envsPerThread{};\n    std::vector<std::thread> backgroundThreads;\n    std::vector<Task> currTasks;\n    std::condition_variable cvTask;\n    std::mutex mutex;\n    std::atomic<int> numReady = 0;\n};\n\n}"
  },
  {
    "path": "src/libs/env/include/env/voxel_state.hpp",
    "content": "#pragma once\n\n#include <env/const.hpp>\n#include <env/physics.hpp>\n\n\nnamespace Megaverse\n{\n\nenum VoxelType\n{\n    VOXEL_EMPTY = 0,        // is not a part of the layout, but may contain an object, so there's still entry in the voxel grid\n    VOXEL_SOLID = 0b1,        // whether a voxel requires collision or not, i.e. a regular layout\n    VOXEL_OPAQUE = 0b10,  // whether a voxel needs to be drawn on screen, don't set this if you want an invisible wall\n};\n\nstruct VoxelState\n{\n    VoxelState()\n    : voxelType{VOXEL_EMPTY}\n    , terrain{0}\n    {\n    }\n\n    bool solid() const { return voxelType & VOXEL_SOLID; }\n    bool empty() const { return !solid(); }\n    bool opaque() const { return voxelType & VOXEL_OPAQUE; }\n\n    static uint8_t generateType(bool solid, bool opaque)\n    {\n        return solid | (opaque << 1);\n    }\n\npublic:\n    uint8_t voxelType{}, terrain{};\n    ColorRgb color{ColorRgb::LAYOUT_DEFAULT};\n};\n\ntemplate<typename VoxelT>\nauto makeVoxel(int type, int terrain = 0, ColorRgb color = ColorRgb::LAYOUT_DEFAULT)\n{\n    VoxelT v;\n    v.voxelType = type, v.terrain = terrain, v.color = color;\n    return v;\n}\n\n}"
  },
  {
    "path": "src/libs/env/src/agent.cpp",
    "content": "#include <memory>\n\n#include <Magnum/Magnum.h>\n#include <Magnum/SceneGraph/Camera.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n\n#include <env/agent.hpp>\n#include <env/env_renderer.hpp>\n\n\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\nusing namespace Megaverse;\n\n\nAbstractAgent::AbstractAgent(Object3D *parent, btDynamicsWorld &bWorld, float verticalLookLimitRad)\n: Object(parent)\n, verticalLookLimitRad{verticalLookLimitRad}\n, bWorld(bWorld)\n{\n}\n\n\nDefaultKinematicAgent::DefaultKinematicAgent(Object3D *parent, btDynamicsWorld &bWorld, const Vector3 &startingPosition,\n                                             float rotationRad, float verticalLookLimitRad)\n: AbstractAgent(parent, bWorld, verticalLookLimitRad)\n, cameraObject{&(addChild<Object3D>())}\n, camera{&(cameraObject->addFeature<SceneGraph::Camera3D>())}\n, pickupSpot{&(cameraObject->addChild<Object3D>())}\n{\n    // cameraObject.rotateY(0.0_degf);\n    cameraObject->translate(Magnum::Vector3{0, 0.41f, 0});\n\n    auto [fov, near, far, aspectRatio] = agentCameraParameters();\n    camera->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)\n           .setProjectionMatrix(Matrix4::perspectiveProjection(Deg(fov), aspectRatio, near, far))\n           .setViewport(GL::defaultFramebuffer.viewport().size());\n\n    pickupSpot->translate({0.0f, -0.44f, -1.0f});\n\n    btTransform startTransform;\n    startTransform.setIdentity();\n    startTransform.setRotation(btQuaternion(btVector3(0, 1, 0), rotationRad));\n    startTransform.setOrigin (btVector3(startingPosition.x(), startingPosition.y() + getAgentHeight(), startingPosition.z()));\n    ghostObject.setWorldTransform(startTransform);\n\n    // btScalar characterHeight = 1.0f;  //1.6\n    // btScalar characterRadius = 0.25f;\n    // capsuleShape = std::make_unique<btBoxShape>(btVector3{characterRadius, agentHeight / 2, characterRadius});\n\n    btScalar characterHeight = 1.05f;  //1.6\n    btScalar characterRadius = 0.33f;\n    capsuleShape = std::make_unique<btCapsuleShape>(characterRadius, characterHeight);\n\n    ghostObject.setCollisionShape(capsuleShape.get());\n    ghostObject.setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);\n\n    auto stepHeight = btScalar(0.2f);\n    bCharacter = std::make_unique<KinematicCharacterController>(&ghostObject, capsuleShape.get(), stepHeight, btVector3(0.0, 1.0, 0.0));\n\n//    bWorld.addCollisionObject(&ghostObject, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter);\n    bWorld.addCollisionObject(&ghostObject, btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::DefaultFilter);\n    bWorld.addAction(bCharacter.get());\n}\n\nDefaultKinematicAgent::~DefaultKinematicAgent()\n{\n    bWorld.removeCollisionObject(&ghostObject);\n    bWorld.removeAction(bCharacter.get());\n}\n\nvoid DefaultKinematicAgent::updateTransform()\n{\n    auto worldTrans = ghostObject.getWorldTransform();\n\n    auto position = Vector3{worldTrans.getOrigin()};\n    const auto axis = Vector3{worldTrans.getRotation().getAxis()};\n    const auto normalizedAxis = axis.normalized();\n    const Float rotation = worldTrans.getRotation().getAngle();\n\n    /* Bullet sometimes reports NaNs for all the parameters and nobody is sure\n       why: https://pybullet.org/Bullet/phpBB3/viewtopic.php?t=12080. The body\n       gets stuck in that state, so print the warning just once. */\n    if (Math::isNan(position).any() || Math::isNan(rotation)) {\n        Error{} << \"BulletIntegration::MotionState: Bullet reported NaN transform for\" << this << Debug::nospace << \", ignoring\";\n        return;\n    }\n\n    if (Math::isNan(normalizedAxis).any()) {\n        Error{} << \"BulletIntegration::MotionState: NaN normalized axis\" << this << Debug::nospace << \", ignoring\";\n        return;\n    }\n\n    position += Vector3{0, 0.05f, 0.0f};\n\n    this->resetTransformation().rotate(Rad{rotation}, normalizedAxis).translate(position);\n}\n\nvoid DefaultKinematicAgent::lookLeft(float dt)\n{\n    rotateYAxis(rotateRadians * dt);\n}\n\nvoid DefaultKinematicAgent::lookRight(float dt)\n{\n    rotateYAxis(-rotateRadians * dt);\n}\n\nvoid DefaultKinematicAgent::lookUp(float dt)\n{\n    cameraObject->rotateXLocal(Math::Rad<float>(-currXRotation));\n    currXRotation += rotateXRadians * dt;\n    currXRotation = std::min(verticalLookLimitRad, currXRotation);\n    cameraObject->rotateXLocal(Math::Rad<float>(currXRotation));\n}\n\nvoid DefaultKinematicAgent::lookDown(float dt)\n{\n    cameraObject->rotateXLocal(Math::Rad<float>(-currXRotation));\n    // this is a hack, in the beginning of training the agents really love to look at the sky and can't learn anything\n    // by making looking down easier than up I hope to prevent this\n    currXRotation -= rotateXRadians * dt * 1.1f;\n    currXRotation = std::max(-verticalLookLimitRad, currXRotation);\n    cameraObject->rotateXLocal(Math::Rad<float>(currXRotation));\n}\n\nvoid DefaultKinematicAgent::rotateYAxis(float radians)\n{\n    btMatrix3x3 orn = ghostObject.getWorldTransform().getBasis();\n    orn *= btMatrix3x3(btQuaternion(btVector3(0, 1, 0), radians));\n    ghostObject.getWorldTransform ().setBasis(orn);\n}\n\nbtVector3 DefaultKinematicAgent::forwardDirection() const\n{\n    auto xform = ghostObject.getWorldTransform ();\n    btVector3 forwardDir = xform.getBasis()[2];\n    forwardDir.setZ(-forwardDir.z());\n    // TLOG(INFO) << \"forwardDir: \" << forwardDir.x() << \" \" << forwardDir.y() << \" \" << forwardDir.z();\n    return forwardDir.normalize();\n}\n\nbtVector3 DefaultKinematicAgent::strafeLeftDirection() const\n{\n    auto xform = ghostObject.getWorldTransform ();\n    btVector3 sidewaysDir = xform.getBasis()[0];\n    sidewaysDir.setX(-sidewaysDir.x());\n    return sidewaysDir.normalize();\n}\n\nvoid DefaultKinematicAgent::accelerate(const btVector3 &acc, btScalar frameDuration)\n{\n    bCharacter->setAcceleration(acc, frameDuration);\n}\n\nvoid DefaultKinematicAgent::jump()\n{\n    if (onGround())\n        bCharacter->jump(btVector3(0, 6.2, 0));\n}\n\nvoid DefaultKinematicAgent::teleport(const btVector3 &position)\n{\n    bCharacter->warp(position);\n}\n\nbool DefaultKinematicAgent::onGround() const\n{\n    return bCharacter->onGround();\n}\n"
  },
  {
    "path": "src/libs/env/src/env.cpp",
    "content": "#include <random>\n\n#include <Magnum/SceneGraph/Camera.h>\n\n#include <util/tiny_logger.hpp>\n\n#include <env/env.hpp>\n#include <env/scenario.hpp>\n\n\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\nusing namespace Megaverse;\n\n\n/**\nLeft = 1 << 1,\nRight = 1 << 2,\n\nForward = 1 << 3,\nBackward = 1 << 4,\n\nLookLeft = 1 << 5,\nLookRight = 1 << 6,\n\nJump = 1 << 7,\nInteract = 1 << 8,\n\nLookDown = 1 << 9,\nLookUp = 1 << 10,\n**/\nconst std::vector<int> Env::actionSpaceSizes = {3, 3, 3, 2, 2, 3};\n\n\nEnv::Env(const std::string &scenarioName, int numAgents, const FloatParams& customFloatParams)\n    : scenarioName{scenarioName}\n    , state{numAgents}\n    , numAgents{numAgents}\n{\n    scenario = Scenario::create(scenarioName, *this, state);\n    scenario->init();\n    scenario->setCustomParameters(customFloatParams);\n\n    // empty list of drawables for each supported drawable type\n    for (int drawableType = int(DrawableType::First); drawableType < int(DrawableType::NumTypes); ++drawableType)\n        drawables[DrawableType(drawableType)] = std::vector<SceneObjectInfo>{};\n}\n\nEnv::~Env() = default;\n\nvoid Env::seed(int seedValue)\n{\n    state.rng.seed((unsigned long)seedValue);\n}\n\nvoid Env::reset()\n{\n    state.reset();\n\n    auto seed = randRange(0, 1 << 30, state.rng);\n    state.rng.seed((unsigned long)seed);\n    // TLOG(INFO) << \"Using seed \" << seed;\n\n    // remove dangling pointers from the previous episode\n    for (int drawableType = int(DrawableType::First); drawableType < int(DrawableType::NumTypes); ++drawableType)\n        drawables[DrawableType(drawableType)].clear();\n\n    scenario->reset();\n\n    scenario->spawnAgents(state.agents);\n\n    scenario->addEpisodeDrawables(drawables);\n    scenario->addEpisodeAgentsDrawables(drawables);\n    scenario->addUIDrawables(drawables);\n}\n\nvoid Env::setAction(int agentIdx, Action action)\n{\n    state.currAction[agentIdx] = action;\n}\n\nvoid Env::step()\n{\n    std::fill(state.lastReward.begin(), state.lastReward.end(), 0.0f);\n\n    const auto lastFrameDurationSec = state.lastFrameDurationSec;\n\n    for (int i = 0; i < numAgents; ++i) {\n        const auto a = state.currAction[i];\n        const auto &agent = state.agents[i];\n\n        auto acceleration = btVector3{0, 0, 0};\n\n        if (!!(a & Action::Forward))\n            acceleration += agent->forwardDirection();\n        else if (!!(a & Action::Backward))\n            acceleration -= agent->forwardDirection();\n\n        if (!!(a & Action::Left))\n            acceleration += agent->strafeLeftDirection();\n        else if (!!(a & Action::Right))\n            acceleration -= agent->strafeLeftDirection();\n\n        if (!!(a & Action::LookLeft))\n            agent->lookLeft(lastFrameDurationSec);\n        else if (!!(a & Action::LookRight))\n            agent->lookRight(lastFrameDurationSec);\n\n        if (!!(a & Action::LookUp))\n            agent->lookUp(lastFrameDurationSec);\n        else if (!!(a & Action::LookDown))\n            agent->lookDown(lastFrameDurationSec);\n\n        // if (acceleration.length() > 0)\n        //    TLOG(INFO) << \"acc direction: \" << acceleration.x() << \" \" << acceleration.y() << \" \" << acceleration.z();\n\n        agent->accelerate(acceleration, lastFrameDurationSec);\n\n        if (!!(a & Action::Jump))\n            agent->jump();\n    }\n\n    scenario->preStep();\n\n    state.physics->bWorld.stepSimulation(lastFrameDurationSec, 1, state.simulationStepSeconds);\n\n    for (auto agent : state.agents)\n        agent->updateTransform();\n\n    scenario->step();\n\n    state.currEpisodeSec += state.lastFrameDurationSec;\n\n    scenario->updateUI();\n\n    if (state.currEpisodeSec >= episodeLengthSec())\n        state.done = true;\n\n    // clear the actions\n    for (int i = 0; i < numAgents; ++i)\n        state.currAction[i] = Action::Idle;\n\n    for (int i = 0; i < int(state.agents.size()); ++i) {\n        state.totalReward[i] += state.lastReward[i];\n\n//        if (fabs(state.lastReward[i]) > SIMD_EPSILON)\n//            TLOG(INFO) << \"Last reward for agent #\" << i << \":  \" << state.lastReward[i] << \", total reward:  \" << state.totalReward[i];\n    }\n\n    ++state.numFrames;\n}\n\nstd::vector<Magnum::Color3> Env::getPalette() const\n{\n    return scenario->getPalette();\n}\n\nfloat Env::episodeLengthSec() const\n{\n    return scenario->episodeLengthSec();\n}\n\nfloat Env::trueObjective(int agentIdx) const\n{\n    return scenario->trueObjective(agentIdx);\n}\n\nvoid Env::terminateEpisodeOnNextFrame()\n{\n    scenario->doneWithTimer(0.001f);\n}\n"
  },
  {
    "path": "src/libs/env/src/kinematic_character_controller.cpp",
    "content": "#include <stdio.h>\n#include \"LinearMath/btIDebugDraw.h\"\n#include \"BulletCollision/CollisionDispatch/btGhostObject.h\"\n#include \"BulletCollision/CollisionShapes/btMultiSphereShape.h\"\n#include \"BulletCollision/BroadphaseCollision/btOverlappingPairCache.h\"\n#include \"BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h\"\n#include \"BulletCollision/CollisionDispatch/btCollisionWorld.h\"\n#include \"LinearMath/btDefaultMotionState.h\"\n\n#include <env/kinematic_character_controller.hpp>\n#include <util/tiny_logger.hpp>\n\n\nusing namespace Megaverse;\n\n\n#ifdef UNUSED_FUNCTION\nstatic btVector3 getNormalizedVector(const btVector3& v)\n{\n    btVector3 n(0, 0, 0);\n    if (v.length() > SIMD_EPSILON)\n        n = v.normalized();\n    return n;\n}\n#endif\n\n///@todo Interact with dynamic objects,\n///Ride kinematicly animated platforms properly\n///More realistic (or maybe just a config option) falling\n/// -> Should integrate falling velocity manually and use that in stepDown()\n///Support jumping\n///Support ducking\nclass KinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback\n{\npublic:\n    KinematicClosestNotMeRayResultCallback(btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))\n    {\n        m_me = me;\n    }\n\n    virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)\n    {\n        if (rayResult.m_collisionObject == m_me)\n            return 1.0;\n\n        return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);\n    }\n\nprotected:\n    btCollisionObject* m_me;\n};\n\nclass KinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback\n{\npublic:\n    KinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)\n        : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), m_me(me), m_up(up), m_minSlopeDot(minSlopeDot)\n    {\n    }\n\n    virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)\n    {\n        if (convexResult.m_hitCollisionObject == m_me)\n            return btScalar(1.0);\n\n        if (!convexResult.m_hitCollisionObject->hasContactResponse())\n            return btScalar(1.0);\n\n        btVector3 hitNormalWorld;\n        if (normalInWorldSpace)\n        {\n            hitNormalWorld = convexResult.m_hitNormalLocal;\n        }\n        else\n        {\n            ///need to transform normal into worldspace\n            hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal;\n        }\n\n        btScalar dotUp = m_up.dot(hitNormalWorld);\n        if (dotUp < m_minSlopeDot)\n        {\n            return btScalar(1.0);\n        }\n\n        return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);\n    }\n\nprotected:\n    btCollisionObject* m_me;\n    const btVector3 m_up;\n    btScalar m_minSlopeDot;\n};\n\n/*\n * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'\n *\n * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html\n */\nbtVector3 KinematicCharacterController::computeReflectionDirection(const btVector3& direction, const btVector3& normal)\n{\n    return direction - (btScalar(2.0) * direction.dot(normal)) * normal;\n}\n\n/*\n * Returns the portion of 'direction' that is parallel to 'normal'\n */\nbtVector3 KinematicCharacterController::parallelComponent(const btVector3& direction, const btVector3& normal)\n{\n    btScalar magnitude = direction.dot(normal);\n    return normal * magnitude;\n}\n\n/*\n * Returns the portion of 'direction' that is perpindicular to 'normal'\n */\nbtVector3 KinematicCharacterController::perpindicularComponent(const btVector3& direction, const btVector3& normal)\n{\n    return direction - parallelComponent(direction, normal);\n}\n\nKinematicCharacterController::KinematicCharacterController(btPairCachingGhostObject* ghostObject, btConvexShape* convexShape, btScalar stepHeight, const btVector3& up)\n{\n    m_ghostObject = ghostObject;\n    m_up.setValue(0.0f, 1.0f, 0.0f);\n    m_jumpAxis.setValue(0.0f, 1.0f, 0.0f);\n    horizontalVelocity.setValue(0.0, 0.0, 0.0);\n\n    m_AngVel.setValue(0.0, 0.0, 0.0);\n    m_useGhostObjectSweepTest = true;\n    m_turnAngle = btScalar(0.0);\n    m_convexShape = convexShape;\n    m_verticalVelocity = 0.0;\n    m_verticalOffset = 0.0;\n    m_fallSpeed = 55.0;     // Terminal velocity of a sky diver in m/s.\n    m_jumpSpeed = 10.0;     // ?\n    m_SetjumpSpeed = m_jumpSpeed;\n    m_wasOnGround = false;\n    m_wasJumping = false;\n    m_interpolateUp = true;\n    m_currentStepOffset = 0.0;\n    m_angularDamping = btScalar(0.0);\n\n    setUp(up);\n    setStepHeight(stepHeight);\n    setMaxSlope(btRadians(45.0));\n}\n\nKinematicCharacterController::~KinematicCharacterController() = default;\n\nbtPairCachingGhostObject* KinematicCharacterController::getGhostObject()\n{\n    return m_ghostObject;\n}\n\nbool KinematicCharacterController::recoverFromPenetration(btCollisionWorld* collisionWorld, int /*iteration*/)\n{\n    // Here we must refresh the overlapping paircache as the penetrating movement itself or the\n    // previous recovery iteration might have used setWorldTransform and pushed us into an object\n    // that is not in the previous cache contents from the last timestep, as will happen if we\n    // are pushed into a new AABB overlap. Unhandled this means the next convex sweep gets stuck.\n    //\n    // Do this by calling the broadphase's setAabb with the moved AABB, this will update the broadphase\n    // paircache and the ghostobject's internal paircache at the same time.    /BW\n\n    btVector3 minAabb, maxAabb;\n    m_convexShape->getAabb(m_ghostObject->getWorldTransform(), minAabb, maxAabb);\n    collisionWorld->getBroadphase()->setAabb(m_ghostObject->getBroadphaseHandle(),\n                                             minAabb,\n                                             maxAabb,\n                                             collisionWorld->getDispatcher());\n\n    bool penetration = false;\n\n    collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());\n\n    m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();\n\n    const auto overlappingPairCache = m_ghostObject->getOverlappingPairCache();\n    const auto numOverlappingPairs = overlappingPairCache->getNumOverlappingPairs();\n    for (int i = 0; i < numOverlappingPairs && !penetration; ++i) {\n        m_manifoldArray.resize(0);\n\n        btBroadphasePair* collisionPair = &overlappingPairCache->getOverlappingPairArray()[i];\n\n        auto * obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);\n        auto * obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);\n\n        if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse()))\n            continue;\n\n        if (!needsCollision(obj0, obj1))\n            continue;\n\n        if (collisionPair->m_algorithm)\n            collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);\n\n        for (int j = 0; j < m_manifoldArray.size() && !penetration; j++) {\n            btPersistentManifold* manifold = m_manifoldArray[j];\n            btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);\n            for (int p = 0; p < manifold->getNumContacts(); p++) {\n                const btManifoldPoint& pt = manifold->getContactPoint(p);\n\n                btScalar dist = pt.getDistance();\n\n                if (dist < -m_maxPenetrationDepth) {\n                    auto posDelta = pt.m_normalWorldOnB * directionSign * dist;\n                    m_currentPosition += posDelta;\n                    penetration = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    btTransform newTrans = m_ghostObject->getWorldTransform();\n    newTrans.setOrigin(m_currentPosition);\n    m_ghostObject->setWorldTransform(newTrans);\n    //\tprintf(\"m_touchingNormal = %f,%f,%f\\n\",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);\n    return penetration;\n}\n\nvoid KinematicCharacterController::stepUp(btCollisionWorld* world)\n{\n    btScalar stepHeight = 0.0f;\n    if (m_verticalVelocity < 0.0)\n        stepHeight = m_stepHeight;\n\n    // phase 1: up\n    btTransform start, end;\n\n    start.setIdentity();\n    end.setIdentity();\n\n    /* FIXME: Handle penetration properly */\n    start.setOrigin(m_currentPosition);\n\n    m_targetPosition = m_currentPosition + m_up * (stepHeight) + m_jumpAxis * ((m_verticalOffset > 0.f ? m_verticalOffset : 0.f));\n    m_currentPosition = m_targetPosition;\n\n    end.setOrigin(m_targetPosition);\n\n    start.setRotation(m_currentOrientation);\n    end.setRotation(m_targetOrientation);\n\n    KinematicClosestNotMeConvexResultCallback callback(m_ghostObject, -m_up, m_maxSlopeCosine);\n    callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;\n    callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;\n\n    if (m_useGhostObjectSweepTest)\n    {\n        m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);\n    }\n    else\n    {\n        world->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);\n    }\n\n    if (callback.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject))\n    {\n        // Only modify the position if the hit was a slope and not a wall or ceiling.\n        if (callback.m_hitNormalWorld.dot(m_up) > 0.0)\n        {\n            // we moved up only a fraction of the step height\n            m_currentStepOffset = stepHeight * callback.m_closestHitFraction;\n            if (m_interpolateUp == true)\n                m_currentPosition.setInterpolate3(m_currentPosition, m_targetPosition, callback.m_closestHitFraction);\n            else\n                m_currentPosition = m_targetPosition;\n        }\n\n        btTransform& xform = m_ghostObject->getWorldTransform();\n        xform.setOrigin(m_currentPosition);\n        m_ghostObject->setWorldTransform(xform);\n\n        // fix penetration if we hit a ceiling for example\n        int numPenetrationLoops = 0;\n        m_touchingContact = false;\n        while (recoverFromPenetration(world, numPenetrationLoops))\n        {\n            numPenetrationLoops++;\n            m_touchingContact = true;\n            if (numPenetrationLoops > 4)\n            {\n                //printf(\"character could not recover from penetration = %d\\n\", numPenetrationLoops);\n                break;\n            }\n        }\n        m_targetPosition = m_ghostObject->getWorldTransform().getOrigin();\n        m_currentPosition = m_targetPosition;\n\n        if (m_verticalOffset > 0)\n        {\n            m_verticalOffset = 0.0;\n            m_verticalVelocity = 0.0;\n            m_currentStepOffset = m_stepHeight;\n        }\n    }\n    else\n    {\n        m_currentStepOffset = stepHeight;\n        m_currentPosition = m_targetPosition;\n    }\n}\n\nbool KinematicCharacterController::needsCollision(const btCollisionObject* body0, const btCollisionObject* body1)\n{\n    bool collides = (body0->getBroadphaseHandle()->m_collisionFilterGroup & body1->getBroadphaseHandle()->m_collisionFilterMask) != 0;\n    collides = collides && (body1->getBroadphaseHandle()->m_collisionFilterGroup & body0->getBroadphaseHandle()->m_collisionFilterMask);\n    return collides;\n}\n\nvoid KinematicCharacterController::updateTargetPositionBasedOnCollision(const btVector3& hitNormal, btScalar fraction)\n{\n    btVector3 movementDirection = m_targetPosition - m_currentPosition;\n    btScalar movementLength = movementDirection.length();\n    if (movementLength > SIMD_EPSILON) {\n        movementDirection.normalize();\n\n        auto parallelDir = parallelComponent(movementDirection, hitNormal);\n        auto perpindicularDir = perpindicularComponent(movementDirection, hitNormal);\n\n        m_targetPosition = m_currentPosition;\n\n        // arrest the momentum in the direction of the normal, continue movement in the perpendicular direction\n        m_targetPosition += perpindicularDir * btScalar(movementLength);\n        m_targetPosition += parallelDir * btScalar(movementLength * fraction);\n    }\n}\n\n/**\n * Phase 2: react to directional user input\n * @param collisionWorld\n * @param horizontalVelocity\n * @param dt\n */\nvoid KinematicCharacterController::stepForwardAndStrafe(btCollisionWorld* collisionWorld, const btVector3& horizontalVelocity, btScalar dt)\n{\n    m_targetPosition = m_currentPosition + horizontalVelocity * dt;\n\n    btTransform start, end;\n    start.setIdentity();\n    end.setIdentity();\n\n    int maxIter = 10, iteration = 0;\n\n    while (maxIter-- > 0) {\n        ++iteration;\n\n        start.setOrigin(m_currentPosition);\n        end.setOrigin(m_targetPosition);\n        btVector3 sweepDirNegative(m_currentPosition - m_targetPosition);\n\n        start.setRotation(m_currentOrientation);\n        end.setRotation(m_targetOrientation);\n\n        KinematicClosestNotMeConvexResultCallback callback(m_ghostObject, sweepDirNegative, btScalar(0.0));\n        callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;\n        callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;\n\n        if (!(start == end)) {\n            // desired movement is > 0\n            m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);\n        }\n\n        if (callback.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject)) {\n            // we moved only a fraction\n            updateTargetPositionBasedOnCollision(callback.m_hitNormalWorld, callback.m_closestHitFraction);\n            btVector3 currentDir = m_targetPosition - m_currentPosition;\n\n            auto distance2 = currentDir.length2();\n            if (distance2 > 0.0001f) {\n                currentDir.normalize();\n\n                /* See Quake2: \"If velocity is against original velocity, stop dead to avoid tiny oscilations in sloping corners.\" */\n                if (currentDir.dot(horizontalVelocity) <= btScalar(0.0)) {\n                    // cancel the movement\n                    m_targetPosition = m_currentPosition;\n                    break;\n                }\n            } else {\n                // cancel the movement\n                m_targetPosition = m_currentPosition;\n                break;\n            }\n\n        } else {\n            break;\n        }\n    }\n\n    m_currentPosition = m_targetPosition;\n}\n\n\n/** phase 3: down\n * @param collisionWorld\n * @param dt\n */\nvoid KinematicCharacterController::stepDown(btCollisionWorld *collisionWorld, btScalar dt)\n{\n    btScalar downVelocity = (m_verticalVelocity < 0.f ? -m_verticalVelocity : 0.f);\n\n    // limit fall terminal velocity??\n    if (downVelocity > 0.0 && downVelocity > m_fallSpeed && (m_wasOnGround || !m_wasJumping))\n        downVelocity = m_fallSpeed;\n\n    btVector3 step_drop = m_up * (m_currentStepOffset + downVelocity * dt);\n    m_targetPosition -= step_drop;\n\n    KinematicClosestNotMeConvexResultCallback callback(m_ghostObject, m_up, m_maxSlopeCosine);\n    callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;\n    callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;\n\n    {\n        btTransform start, end;\n        start.setIdentity();\n        end.setIdentity();\n\n        start.setOrigin(m_currentPosition);\n        end.setOrigin(m_targetPosition);\n        start.setRotation(m_currentOrientation);\n        end.setRotation(m_targetOrientation);\n\n        m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);\n    }\n\n    if ((m_ghostObject->hasContactResponse() && (callback.hasHit() && needsCollision(m_ghostObject, callback.m_hitCollisionObject)))) {\n        // we dropped a fraction of the height and hit the floor\n\n        // because of allowed penetration this will move us more downwards than we need to (we penetrate the floor polygon)\n        // this should be handled later by recoverFromPenetration?\n        m_currentPosition.setInterpolate3(m_currentPosition, m_targetPosition, callback.m_closestHitFraction);\n\n        m_verticalVelocity = 0.0;\n        m_verticalOffset = 0.0;\n        m_wasJumping = false;\n    } else {\n        // we dropped the full height, didn't hit anything\n        m_currentPosition = m_targetPosition;\n    }\n}\n\n\nvoid KinematicCharacterController::setWalkDirection(\n    const btVector3& walkDirection)\n{\n    horizontalVelocity = walkDirection;\n}\n\nvoid KinematicCharacterController::setAngularVelocity(const btVector3& velocity)\n{\n    m_AngVel = velocity;\n}\n\nconst btVector3& KinematicCharacterController::getAngularVelocity() const\n{\n    return m_AngVel;\n}\n\nvoid KinematicCharacterController::setLinearVelocity(const btVector3& velocity)\n{\n    horizontalVelocity = velocity;\n\n    // HACK: if we are moving in the direction of the up, treat it as a jump :(\n    if (horizontalVelocity.length2() > 0)\n    {\n        btVector3 w = velocity.normalized();\n        btScalar c = w.dot(m_up);\n        if (c != 0)\n        {\n            //there is a component in walkdirection for vertical velocity\n            btVector3 upComponent = m_up * (btSin(SIMD_HALF_PI - btAcos(c)) * horizontalVelocity.length());\n            horizontalVelocity -= upComponent;\n            m_verticalVelocity = (c < 0.0f ? -1 : 1) * upComponent.length();\n\n            if (c > 0.0f)\n            {\n                m_wasJumping = true;\n                m_jumpPosition = m_ghostObject->getWorldTransform().getOrigin();\n            }\n        }\n    }\n    else\n        m_verticalVelocity = 0.0f;\n}\n\nbtVector3 KinematicCharacterController::getLinearVelocity() const\n{\n    return horizontalVelocity + (m_verticalVelocity * m_up);\n}\n\nvoid KinematicCharacterController::reset(btCollisionWorld* collisionWorld)\n{\n    m_verticalVelocity = 0.0;\n    m_verticalOffset = 0.0;\n    m_wasOnGround = false;\n    m_wasJumping = false;\n    horizontalVelocity.setValue(0, 0, 0);\n\n    //clear pair cache\n    btHashedOverlappingPairCache* cache = m_ghostObject->getOverlappingPairCache();\n    while (cache->getOverlappingPairArray().size() > 0)\n    {\n        cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher());\n    }\n}\n\nvoid KinematicCharacterController::warp(const btVector3& origin)\n{\n    btTransform xform;\n    xform.setIdentity();\n    xform.setOrigin(origin);\n    m_ghostObject->setWorldTransform(xform);\n    horizontalVelocity.setValue(0, 0, 0);\n    m_verticalVelocity = 0;\n}\n\nvoid KinematicCharacterController::preStep(btCollisionWorld* /*collisionWorld*/)\n{\n    m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();\n    m_targetPosition = m_currentPosition;\n\n    m_currentOrientation = m_ghostObject->getWorldTransform().getRotation();\n    m_targetOrientation = m_currentOrientation;\n}\n\nvoid KinematicCharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar dt)\n{\n    const auto originalPosition = m_currentPosition;\n\n    if (m_AngVel.length2() > 0.0f)\n        m_AngVel *= btPow(btScalar(1) - m_angularDamping, dt);\n\n    // integrate for angular velocity\n    if (m_AngVel.length2() > 0.0f)\n    {\n        btTransform xform = m_ghostObject->getWorldTransform();\n\n        btQuaternion rot(m_AngVel.normalized(), m_AngVel.length() * dt);\n\n        btQuaternion orn = rot * xform.getRotation();\n\n        xform.setRotation(orn);\n        m_ghostObject->setWorldTransform(xform);\n\n        m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();\n        m_targetPosition = m_currentPosition;\n        m_currentOrientation = m_ghostObject->getWorldTransform().getRotation();\n        m_targetOrientation = m_currentOrientation;\n    }\n\n    m_wasOnGround = onGround();\n\n    // Update fall velocity.\n    m_verticalVelocity -= m_gravity * dt;\n\n    if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)\n        m_verticalVelocity = m_jumpSpeed;\n\n    if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))\n        m_verticalVelocity = -btFabs(m_fallSpeed);\n\n    m_verticalOffset = m_verticalVelocity * dt;\n\n    btTransform xform;\n    xform = m_ghostObject->getWorldTransform();\n\n    stepUp(collisionWorld);\n    stepForwardAndStrafe(collisionWorld, horizontalVelocity, dt);\n    stepDown(collisionWorld, dt);\n\n    xform.setOrigin(m_currentPosition);\n    m_ghostObject->setWorldTransform(xform);\n\n    // how far we actually traveled. If we hit a wall this will arrest the momentum\n    horizontalVelocity = (m_currentPosition - originalPosition) / dt;\n    horizontalVelocity.setY(0);  // we only care about velocity in horizontal plane\n\n    int numPenetrationLoops = 0;\n    m_touchingContact = false;\n    while (recoverFromPenetration(collisionWorld, numPenetrationLoops))\n    {\n        numPenetrationLoops++;\n        m_touchingContact = true;\n        if (numPenetrationLoops > 4)\n            break;\n    }\n\n    auto currHorizontalSpeed = horizontalVelocity.length();\n\n    if (onGround()) {\n        // friction\n\n        if (currHorizontalSpeed - normalDeceleration * dt < 0)\n            horizontalVelocity.setZero();\n        else\n            horizontalVelocity *= (currHorizontalSpeed - normalDeceleration * dt) / currHorizontalSpeed;\n    }\n\n//     TLOG(INFO) << \"Horizontal speed: \" << horizontalVelocity.length();\n}\n\nvoid KinematicCharacterController::setFallSpeed(btScalar fallSpeed)\n{\n    m_fallSpeed = fallSpeed;\n}\n\nvoid KinematicCharacterController::setJumpSpeed(btScalar jumpSpeed)\n{\n    m_jumpSpeed = jumpSpeed;\n    m_SetjumpSpeed = m_jumpSpeed;\n}\n\nvoid KinematicCharacterController::setMaxJumpHeight(btScalar maxJumpHeight)\n{\n    m_maxJumpHeight = maxJumpHeight;\n}\n\nbool KinematicCharacterController::canJump() const\n{\n    return onGround();\n}\n\nvoid KinematicCharacterController::jump(const btVector3& v)\n{\n    m_jumpSpeed = v.length2() == 0 ? m_SetjumpSpeed : v.length();\n    m_verticalVelocity = m_jumpSpeed;\n    m_wasJumping = true;\n\n    m_jumpAxis = v.length2() == 0 ? m_up : v.normalized();\n\n    m_jumpPosition = m_ghostObject->getWorldTransform().getOrigin();\n\n#if 0\n    currently no jumping.\n\tbtTransform xform;\n\tm_rigidBody->getMotionState()->getWorldTransform (xform);\n\tbtVector3 up = xform.getBasis()[1];\n\tup.normalize ();\n\tbtScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);\n\tm_rigidBody->applyCentralImpulse (up * magnitude);\n#endif\n}\n\nvoid KinematicCharacterController::setGravity(const btVector3& gravity)\n{\n    if (gravity.length2() > 0) setUpVector(-gravity);\n\n    m_gravity = gravity.length();\n}\n\nbtVector3 KinematicCharacterController::getGravity() const\n{\n    return -m_gravity * m_up;\n}\n\nvoid KinematicCharacterController::setMaxSlope(btScalar slopeRadians)\n{\n    m_maxSlopeRadians = slopeRadians;\n    m_maxSlopeCosine = btCos(slopeRadians);\n}\n\nbtScalar KinematicCharacterController::getMaxSlope() const\n{\n    return m_maxSlopeRadians;\n}\n\nvoid KinematicCharacterController::setMaxPenetrationDepth(btScalar d)\n{\n    m_maxPenetrationDepth = d;\n}\n\nbtScalar KinematicCharacterController::getMaxPenetrationDepth() const\n{\n    return m_maxPenetrationDepth;\n}\n\nbool KinematicCharacterController::onGround() const\n{\n    return (fabs(m_verticalVelocity) < SIMD_EPSILON) && (fabs(m_verticalOffset) < SIMD_EPSILON);\n}\n\nvoid KinematicCharacterController::setStepHeight(btScalar h)\n{\n    m_stepHeight = h;\n}\n\nbtVector3* KinematicCharacterController::getUpAxisDirections()\n{\n    static btVector3 sUpAxisDirection[3] = {btVector3(1.0f, 0.0f, 0.0f), btVector3(0.0f, 1.0f, 0.0f), btVector3(0.0f, 0.0f, 1.0f)};\n\n    return sUpAxisDirection;\n}\n\nvoid KinematicCharacterController::debugDraw(btIDebugDraw* /*debugDrawer*/)\n{\n}\n\nvoid KinematicCharacterController::setUpInterpolate(bool value)\n{\n    m_interpolateUp = value;\n}\n\nvoid KinematicCharacterController::setUp(const btVector3& up)\n{\n    if (up.length2() > 0 && m_gravity > 0.0f)\n    {\n        setGravity(-m_gravity * up.normalized());\n        return;\n    }\n\n    setUpVector(up);\n}\n\nvoid KinematicCharacterController::setUpVector(const btVector3& up)\n{\n    if (m_up == up)\n        return;\n\n    btVector3 u = m_up;\n\n    if (up.length2() > 0)\n        m_up = up.normalized();\n    else\n        m_up = btVector3(0.0, 0.0, 0.0);\n\n    if (!m_ghostObject) return;\n    btQuaternion rot = getRotation(m_up, u);\n\n    //set orientation with new up\n    btTransform xform;\n    xform = m_ghostObject->getWorldTransform();\n    btQuaternion orn = rot.inverse() * xform.getRotation();\n    xform.setRotation(orn);\n    m_ghostObject->setWorldTransform(xform);\n}\n\nbtQuaternion KinematicCharacterController::getRotation(btVector3& v0, btVector3& v1) const\n{\n    if (v0.length2() == 0.0f || v1.length2() == 0.0f) {\n        btQuaternion q;\n        return q;\n    }\n\n    return shortestArcQuatNormalize2(v0, v1);\n}\n\n/**\n * @param acc acceleration vector\n * @param dt time passed since last frame in seconds\n */\nvoid KinematicCharacterController::setAcceleration(btVector3 acc, btScalar dt)\n{\n    const bool isOnGround = onGround();\n\n    const auto accelerationMagnitude = acc.length();\n    const auto currMaxAcceleration = isOnGround ? maxAcceleration : maxAirAcceleration;\n\n    // we always apply max possible acceleration in the desired direction\n    if (!acc.fuzzyZero())\n        acc *= currMaxAcceleration / accelerationMagnitude;\n\n    if (isOnGround) {\n        // apply acceleration to change velocity\n        horizontalVelocity += acc * dt;\n        const auto currHorizontalSpeed = horizontalVelocity.length();\n\n        // check if we exceed the max speed, decelerate if necessary\n        if (currHorizontalSpeed > maxHorizontalSpeed) {\n            const auto dv = exceedingSpeedLimitDeceleration * dt;\n\n            if (currHorizontalSpeed - dv > maxHorizontalSpeed) {\n                // after applying large deceleration we're still traveling too fast - just subtract the deceleration\n                horizontalVelocity *= (currHorizontalSpeed - dv) / currHorizontalSpeed;\n            } else {\n                // if we just subtract deceleration we'd be traveling too slow\n                // decelerate to max walking speed\n                horizontalVelocity *= maxHorizontalSpeed / currHorizontalSpeed;\n            }\n        }\n    } else {\n        // in the air\n\n        // there is no friction or deceleration\n        const auto currHorizontalSpeed = horizontalVelocity.length();\n        const auto newHorizontalVelocity = horizontalVelocity + acc * dt;\n        const auto newHorizontalSpeed = newHorizontalVelocity.length();\n        if (newHorizontalSpeed <= maxAirSpeed || newHorizontalSpeed < currHorizontalSpeed)\n            horizontalVelocity = newHorizontalVelocity;\n    }\n}\n"
  },
  {
    "path": "src/libs/env/src/vector_env.cpp",
    "content": "#include <env/vector_env.hpp>\n\nusing namespace Megaverse;\n\n\nVectorEnv::VectorEnv(std::vector<std::unique_ptr<Env>> &envs, EnvRenderer &renderer, int numThreads)\n: envs(envs)\n, renderer(renderer)\n, numThreads{numThreads}  // use master threads as one of the threads\n{\n    const int numEnvs = int(envs.size());\n    envsPerThread = (numEnvs / numThreads) + (numEnvs % numThreads != 0);\n\n    currTasks = std::vector<Task>(size_t(numThreads), Task::IDLE);\n\n    for (int i = 1; i < numThreads; ++i) {\n        std::thread t{\n            [this](int threadIdx) {\n\n                while (true) {\n                    std::unique_lock<std::mutex> lock{mutex};\n\n                    while (currTasks[threadIdx] == Task::IDLE)\n                        cvTask.wait(lock);\n\n                    const auto task = currTasks[threadIdx];\n                    currTasks[threadIdx] = Task::IDLE;\n                    lock.unlock();\n\n                    taskFunc(task, threadIdx);\n                    ++numReady;\n\n                    if (task == Task::TERMINATE)\n                        break;\n                }\n            }, i\n        };\n\n        backgroundThreads.emplace_back(std::move(t));\n    }\n\n    done = std::vector<bool>(envs.size());\n    trueObjectives = std::vector<std::vector<float>>(envs.size());\n    for (int envIdx = 0; envIdx < numEnvs; ++envIdx)\n        trueObjectives[envIdx] = std::vector<float>(envs[envIdx]->getNumAgents());\n}\n\nvoid VectorEnv::stepEnv(int envIdx)\n{\n    envs[envIdx]->step();\n    renderer.preDraw(*envs[envIdx], envIdx);\n}\n\nvoid VectorEnv::resetEnv(int envIdx)\n{\n    envs[envIdx]->reset();\n}\n\nvoid VectorEnv::taskFunc(Task task, int threadIdx)\n{\n    auto func = &VectorEnv::stepEnv;\n    if (task == Task::RESET)\n        func = &VectorEnv::resetEnv;\n\n    const auto startIdx = threadIdx * envsPerThread;\n    const auto endIdx = std::min(startIdx + envsPerThread, int(envs.size()));\n    for (int envIdx = startIdx; envIdx < endIdx; ++envIdx)\n        (this->*func)(envIdx);\n}\n\nvoid VectorEnv::executeTask(Task task)\n{\n    numReady = 0;\n\n    std::unique_lock<std::mutex> lock{mutex};\n    for (int threadIdx = 1; threadIdx < numThreads; ++threadIdx)\n        currTasks[threadIdx] = task;\n\n    cvTask.notify_all();\n    lock.unlock();\n\n    taskFunc(task, 0);\n\n    // just waiting on an atomic, this is a bit faster than conditional variable\n    // tradeoff - using more CPU cycles?\n    while (numReady < numThreads - 1);\n}\n\nvoid VectorEnv::step()\n{\n    executeTask(Task::STEP);\n\n    // do this in background thread??\n    for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx) {\n        if (envs[envIdx]->isDone()) {\n            done[envIdx] = true;\n            for (int agentIdx = 0; agentIdx < envs[envIdx]->getNumAgents(); ++agentIdx)\n                trueObjectives[envIdx][agentIdx] = envs[envIdx]->trueObjective(agentIdx);\n            envs[envIdx]->reset();\n            renderer.reset(*envs[envIdx], envIdx);\n            renderer.preDraw(*envs[envIdx], envIdx);\n        } else {\n            done[envIdx] = false;\n        }\n    }\n\n    renderer.draw(envs);\n}\n\nvoid VectorEnv::reset()\n{\n    // reset renderer on the main thread\n    for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx) {\n        envs[envIdx]->reset();\n        renderer.reset(*envs[envIdx], envIdx);\n        renderer.preDraw(*envs[envIdx], envIdx);\n    }\n\n    renderer.draw(envs);\n}\n\nvoid VectorEnv::close()\n{\n    executeTask(Task::TERMINATE);\n    for (auto &t : backgroundThreads)\n        t.join();\n}\n"
  },
  {
    "path": "src/libs/magnum_rendering/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(libgfx-magnum VERSION 0.1 LANGUAGES CXX)\n\nadd_library_default(magnum_rendering)\ntarget_link_libraries(magnum_rendering PUBLIC env rendering Corrade::Main Magnum::GL Magnum::Shaders Magnum::MeshTools Magnum::Primitives MagnumIntegration::Bullet)\n\nfind_package (Corrade REQUIRED Main)\nif (NOT CORRADE_TARGET_APPLE)\n    find_package(Magnum REQUIRED WindowlessEglApplication)\n    target_link_libraries(magnum_rendering PUBLIC glad Magnum::WindowlessEglApplication)\nelse ()\n    find_package(Magnum REQUIRED WindowlessCglApplication)\n    target_link_libraries(magnum_rendering PUBLIC Magnum::WindowlessCglApplication)\nendif ()\n"
  },
  {
    "path": "src/libs/magnum_rendering/include/magnum_rendering/magnum_env_renderer.hpp",
    "content": "#pragma once\n\n#include <memory>\n\n#include <Magnum/GL/Renderbuffer.h>\n\n#include <util/magnum.hpp>\n\n#include <env/vector_env.hpp>\n#include <env/env_renderer.hpp>\n\n#include <rendering/render_utils.hpp>\n\n#include <magnum_rendering/rendering_context.hpp>\n\n\nnamespace Megaverse\n{\n\nclass MagnumEnvRenderer : public EnvRenderer\n{\npublic:\n    explicit MagnumEnvRenderer(\n        Envs &envs, int w, int h, bool withDebugDraw = false, bool withOverview = false, RenderingContext *ctx = nullptr\n    );\n\n    ~MagnumEnvRenderer() override;\n\n    void reset(Env &env, int envIdx) override;\n\n    void preDraw(Env &env, int envIdx) override;\n\n    void draw(Envs &envs) override;\n\n    void drawAgent(Env &env, int envIdx, int agentIndex, bool readToBuffer);\n\n    const uint8_t * getObservation(int envIdx, int agentIdx) const override;\n\n    Magnum::GL::Framebuffer *getFramebuffer();\n\n    void toggleDebugMode();\n\n    Overview * getOverview() override;\n\nprivate:\n    struct Impl;\n    std::unique_ptr<Impl> pimpl;\n};\n\n}"
  },
  {
    "path": "src/libs/magnum_rendering/include/magnum_rendering/rendering_context.hpp",
    "content": "#pragma once\n\n#include <memory>\n\n\nnamespace Megaverse\n{\n\nclass RenderingContext\n{\npublic:\n    virtual ~RenderingContext() = default;\n\n    virtual void makeCurrent() = 0;\n};\n\n\nclass WindowRenderingContext : public RenderingContext\n{\npublic:\n    void makeCurrent() override\n    {\n        // noop, this is only for test apps that never switch context\n    }\n};\n\n\nclass WindowlessContext : public RenderingContext\n{\npublic:\n    explicit WindowlessContext(int gpuDevice = 0);\n\n    ~WindowlessContext() override;\n\n    void makeCurrent() override;\n\nprotected:\n    struct Impl;\n    std::unique_ptr<Impl> pimpl;\n};\n\n}"
  },
  {
    "path": "src/libs/magnum_rendering/src/magnum_env_renderer.cpp",
    "content": "#include <Corrade/Containers/GrowableArray.h>\n\n#include <Magnum/GL/Buffer.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n#include <Magnum/GL/Mesh.h>\n#include <Magnum/GL/Renderer.h>\n#include <Magnum/ImageView.h>\n#include <Magnum/Math/Color.h>\n#include <Magnum/Math/Matrix4.h>\n#include <Magnum/Trade/MeshData.h>\n#include <Magnum/Shaders/Phong.h>\n#include <Magnum/SceneGraph/Camera.h>\n#include <Magnum/SceneGraph/Drawable.h>\n#include <Magnum/MeshTools/Compile.h>\n#include <Magnum/GL/RenderbufferFormat.h>\n#include <Magnum/GL/Version.h>\n#include <Magnum/GL/Framebuffer.h>\n#include <Magnum/GL/Renderbuffer.h>\n#include <Magnum/GL/Context.h>\n#include <Magnum/PixelFormat.h>\n#include <Magnum/BulletIntegration/DebugDraw.h>\n\n#include <util/tiny_logger.hpp>\n\n#include <rendering/render_utils.hpp>\n\n#include <magnum_rendering/rendering_context.hpp>\n\n#include <magnum_rendering/magnum_env_renderer.hpp>\n\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\nusing namespace Megaverse;\n\n\nstruct InstanceData {\n    Magnum::Matrix4 transformationMatrix;\n    Magnum::Matrix3x3 normalMatrix;\n    Magnum::Color3 color;\n};\n\n\nclass CustomDrawable : public SceneGraph::Drawable3D\n{\npublic:\n    explicit CustomDrawable(\n        SceneGraph::AbstractObject3D &parentObject,\n        Containers::Array<InstanceData> &instanceData,\n        const Color3 &color,\n        SceneGraph::DrawableGroup3D &drawables\n    )\n    : SceneGraph::Drawable3D{parentObject, &drawables}, _instanceData(instanceData), _color{color}\n    {}\n\nprivate:\n    void draw(const Matrix4& t, SceneGraph::Camera3D&) override {\n        arrayAppend(_instanceData, Containers::InPlaceInit, t, t.normalMatrix(), _color);\n    }\n\n    Containers::Array<InstanceData>& _instanceData;\n    Color3 _color;\n};\n\n\n#ifdef UNUSED\nclass SimpleDrawable3D : public Object3D, public SceneGraph::Drawable3D\n{\npublic:\n    explicit SimpleDrawable3D(SceneGraph::DrawableGroup3D &drawables,\n                              Shaders::Phong & shader, GL::Mesh& mesh, const Color3 &color, Object3D *parentObject)\n        : Object3D{parentObject}\n        , SceneGraph::Drawable3D{*this, &drawables}\n        , _shader(shader), _mesh(mesh), _color(color)\n    {}\n\n    void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) override\n    {\n        _shader.setTransformationMatrix(transformationMatrix)\n            .setNormalMatrix(transformationMatrix.normalMatrix())\n            .setProjectionMatrix(camera.projectionMatrix())\n            .setAmbientColor(0.4 * _color)\n            .setDiffuseColor(_color)\n            .setShininess(150)\n                /* relative to the camera */\n            .setLightPosition({13.0f, 2.0f, 5.0f})\n            .setLightColor(0xaaaaaa_rgbf)\n            .draw(_mesh);\n    }\n\nprivate:\n    Shaders::Phong& _shader;\n    GL::Mesh& _mesh;\n    Color3 _color;\n};\n#endif\n\n\nstruct MagnumEnvRenderer::Impl\n{\npublic:\n    explicit Impl(Envs &envs, int w, int h, bool withDebugDraw = false, bool withOverview = false, RenderingContext *ctx = nullptr);\n\n    ~Impl();\n\n    RenderingContext * initContext(RenderingContext *ctx);\n\n    /**\n     * Reset the state of the renderer between episodes.\n     * @param env\n     */\n    void reset(Env &env, int envIndex);\n\n    void preDraw(Env &env, int envIndex);\n    void draw(Envs &envs);\n    void drawAgent(Env &env, int envIndex, int agentIdx, bool readToBuffer);\n\n    uint8_t * getObservation(int envIdx, int agentIdx);\n\n    GL::Framebuffer * getFramebuffer() { return &framebuffer; }\n\n    void toggleDebugMode() { withDebugDraw = !withDebugDraw; }\n\n    Overview * getOverview() { return &overview; }\n\npublic:\n    std::unique_ptr<WindowlessContext> windowlessContextPtr{nullptr};\n    RenderingContext *ctx = nullptr;\n\n    Vector2i framebufferSize;\n\n    std::vector<SceneGraph::DrawableGroup3D> envDrawables;\n\n    std::map<DrawableType, GL::Buffer> instanceBuffers;\n    std::map<DrawableType, Containers::Array<InstanceData>> instanceData;\n\n    Shaders::Phong shader{NoCreate};\n    Shaders::Phong shaderInstanced{NoCreate};\n\n    GL::Framebuffer framebuffer;\n    GL::Renderbuffer colorBuffer, depthBuffer;\n\n    std::map<DrawableType, Trade::MeshData> meshData;\n    std::map<DrawableType, GL::Mesh> meshes;\n\n    std::vector<std::vector<Containers::Array<uint8_t>>> agentFrames;\n    std::vector<std::vector<std::unique_ptr<MutableImageView2D>>> agentImageViews;\n\n    bool withDebugDraw = false;\n    BulletIntegration::DebugDraw debugDraw{NoCreate};\n\n    bool withOverviewCamera = false;\n\n    Overview overview;\n};\n\n\nMagnumEnvRenderer::Impl::Impl(Envs &envs, int w, int h, bool withDebugDraw, bool withOverview, RenderingContext *ctx)\n: ctx{initContext(ctx)}\n, framebufferSize{w, h}\n, framebuffer{Magnum::Range2Di{{}, framebufferSize}}\n, withDebugDraw{withDebugDraw}\n, withOverviewCamera{withOverview}\n{\n    assert(!envs.empty());\n\n    MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL330);\n\n    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);\n    GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);\n\n    colorBuffer.setStorage(GL::RenderbufferFormat::SRGB8Alpha8, framebufferSize);\n    depthBuffer.setStorage(GL::RenderbufferFormat::DepthComponent24, framebufferSize);\n\n    framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, colorBuffer);\n    framebuffer.attachRenderbuffer(GL::Framebuffer::BufferAttachment::Depth, depthBuffer);\n    framebuffer.mapForDraw({{Shaders::Phong::ColorOutput, GL::Framebuffer::ColorAttachment{0}}});\n\n    framebuffer.clearColor(0, Color3{0.125f}).clearDepth(1.0).bind();\n\n    CORRADE_INTERNAL_ASSERT(framebuffer.checkStatus(GL::FramebufferTarget::Draw) == GL::Framebuffer::Status::Complete);\n\n    TLOG(INFO) << \"Creating Magnum env renderer \" << w << \" \" << h << \" \" << envs.size();\n\n    for (const auto &e : envs) {\n        std::vector<Containers::Array<uint8_t>> envAgentFrames;\n        std::vector<std::unique_ptr<MutableImageView2D>> envAgentImageViews;\n\n        for (int i = 0; i < e->getNumAgents(); ++i) {\n            envAgentFrames.emplace_back(size_t(framebufferSize.x() * framebufferSize.y() * 4));\n            envAgentImageViews.emplace_back(\n                std::make_unique<MutableImageView2D>(PixelFormat::RGBA8Unorm, framebufferSize, envAgentFrames[i])\n            );\n        }\n\n        agentFrames.emplace_back(std::move(envAgentFrames));\n        agentImageViews.emplace_back(std::move(envAgentImageViews));\n    }\n\n    shaderInstanced = Shaders::Phong{Shaders::Phong::Flag::VertexColor | Shaders::Phong::Flag::InstancedTransformation};\n    shaderInstanced.setShininess(300).setLightPosition({0, 4, 2}).setLightColor(0xaaaaaa_rgbf);\n    shaderInstanced.setDiffuseColor(0xbbbbbb_rgbf);\n    shaderInstanced.setAmbientColor(0x555555_rgbf);\n\n    shader = Shaders::Phong{};\n\n    // meshes\n    {\n        initPrimitives(meshData);\n        for (const auto &[drawable, data] : meshData)\n            meshes[drawable] = MeshTools::compile(data);\n\n        for (auto &[k, v] : meshes) {\n            instanceBuffers[k] = GL::Buffer{};\n            v.addVertexBufferInstanced(\n                instanceBuffers[k], 1, 0,\n                Shaders::Phong::TransformationMatrix{},\n                Shaders::Phong::NormalMatrix{},\n                Shaders::Phong::Color3{}\n            );\n        }\n    }\n\n    // drawables\n    {\n        envDrawables = std::vector<SceneGraph::DrawableGroup3D>(envs.size());\n    }\n\n    if (withDebugDraw) {\n        debugDraw = BulletIntegration::DebugDraw{};\n        debugDraw.setMode(BulletIntegration::DebugDraw::Mode::DrawWireframe);\n    }\n}\n\nMagnumEnvRenderer::Impl::~Impl()\n{\n    TLOG(INFO) << __PRETTY_FUNCTION__;\n    if (windowlessContextPtr)\n        windowlessContextPtr->makeCurrent();\n}\n\nRenderingContext * MagnumEnvRenderer::Impl::initContext(RenderingContext *context)\n{\n    if (context) {\n        // we're given a rendering context\n    } else {\n        // don't have an active rendering context, let's create one\n        TLOG(INFO) << windowlessContextPtr.get();\n        windowlessContextPtr = std::make_unique<WindowlessContext>();\n        context = windowlessContextPtr.get();\n    }\n\n    return context;\n}\n\nvoid MagnumEnvRenderer::Impl::reset(Env &env, int envIndex)\n{\n    ctx->makeCurrent();\n\n    // reset renderer data structures\n    {\n        envDrawables[envIndex] = SceneGraph::DrawableGroup3D{};\n\n        for (const auto &it : meshes)\n            arrayResize(instanceData[it.first], 0);\n    }\n\n    // drawables\n    {\n        const auto &drawables = env.getDrawables();\n\n        for (auto &it : meshes) {\n            for (const auto &sceneObjectInfo : drawables.at(it.first)) {\n                const auto &color = sceneObjectInfo.color;\n                sceneObjectInfo.objectPtr->addFeature<CustomDrawable>(instanceData[it.first], color, envDrawables[envIndex]);\n            }\n        }\n    }\n\n    if (withOverviewCamera && envIndex == 0)\n        overview.reset(&env.getScene());\n}\n\nvoid MagnumEnvRenderer::Impl::preDraw(Env &, int)\n{\n}\n\nvoid MagnumEnvRenderer::Impl::drawAgent(Env &env, int envIndex, int agentIdx, bool readToBuffer)\n{\n    framebuffer\n        .clearColor(0, Color3{0})\n        .clearDepth(1.0f)\n        .bind();\n\n    for (auto &it : meshes)\n        arrayResize(instanceData[it.first], 0);\n\n    auto activeCameraPtr = env.getAgents()[agentIdx]->getCamera();\n    if (withOverviewCamera && overview.enabled && envIndex == 0)\n        activeCameraPtr = overview.camera;\n\n    // Would be nice to implement frustrum culling here: https://doc.magnum.graphics/magnum/classMagnum_1_1SceneGraph_1_1Drawable.html#SceneGraph-Drawable-draw-order\n    // Although Vulkan renderer is so much faster, who cares\n    activeCameraPtr->draw(envDrawables[envIndex]);\n\n    shaderInstanced.setProjectionMatrix(activeCameraPtr->projectionMatrix());\n\n    // Upload instance data to the GPU (orphaning the previous buffer contents) and draw all meshes in one call\n    for (auto &[drawableType, mesh] : meshes)\n        if (!instanceData[drawableType].empty()) {\n            instanceBuffers[drawableType].setData(instanceData[drawableType], GL::BufferUsage::DynamicDraw);\n            mesh.setInstanceCount(Int(instanceData[drawableType].size()));\n            shaderInstanced.draw(mesh);\n        }\n\n    // Bullet debug draw\n    if (withDebugDraw) {\n        if (!env.getPhysics().bWorld.getDebugDrawer())\n            env.getPhysics().bWorld.setDebugDrawer(&debugDraw);\n\n        GL::Renderer::setDepthFunction(GL::Renderer::DepthFunction::LessOrEqual);\n        debugDraw.setTransformationProjectionMatrix(activeCameraPtr->projectionMatrix()*activeCameraPtr->cameraMatrix());\n        env.getPhysics().bWorld.debugDrawWorld();\n        GL::Renderer::setDepthFunction(GL::Renderer::DepthFunction::Less);\n    }\n\n    if (readToBuffer) {\n        framebuffer.mapForRead(GL::Framebuffer::ColorAttachment{0});\n        framebuffer.read(framebuffer.viewport(), *agentImageViews[envIndex][agentIdx]);\n    }\n}\n\nvoid MagnumEnvRenderer::Impl::draw(Envs &envs)\n{\n    ctx->makeCurrent();\n\n    for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx)\n        for (int agentIdx = 0; agentIdx < envs[envIdx]->getNumAgents(); ++agentIdx)\n            drawAgent(*envs[envIdx], envIdx, agentIdx, true);\n}\n\nuint8_t * MagnumEnvRenderer::Impl::getObservation(int envIdx, int agentIdx)\n{\n    return agentFrames[envIdx][agentIdx].data();\n}\n\nMagnumEnvRenderer::MagnumEnvRenderer(Envs &envs, int w, int h, bool withDebugDraw, bool withOverview, RenderingContext *ctx)\n{\n    pimpl = std::make_unique<Impl>(envs, w, h, withDebugDraw, withOverview, ctx);\n}\n\nMagnumEnvRenderer::~MagnumEnvRenderer() = default;\n\n\nvoid MagnumEnvRenderer::reset(Env &env, int envIdx)\n{\n    pimpl->reset(env, envIdx);\n}\n\nvoid MagnumEnvRenderer::preDraw(Env &env, int envIdx)\n{\n    pimpl->preDraw(env, envIdx);\n}\n\nvoid MagnumEnvRenderer::draw(Envs &envs)\n{\n    pimpl->draw(envs);\n}\n\nvoid MagnumEnvRenderer::drawAgent(Env &env, int envIndex, int agentIndex, bool readToBuffer)\n{\n    pimpl->drawAgent(env, envIndex, agentIndex, readToBuffer);\n}\n\nconst uint8_t * MagnumEnvRenderer::getObservation(int envIdx, int agentIdx) const\n{\n    return pimpl->getObservation(envIdx, agentIdx);\n}\n\nMagnum::GL::Framebuffer *MagnumEnvRenderer::getFramebuffer()\n{\n    return pimpl->getFramebuffer();\n}\n\nvoid MagnumEnvRenderer::toggleDebugMode()\n{\n    pimpl->toggleDebugMode();\n}\n\nOverview * Megaverse::MagnumEnvRenderer::getOverview()\n{\n    return pimpl->getOverview();\n}\n"
  },
  {
    "path": "src/libs/magnum_rendering/src/rendering_context.cpp",
    "content": "// Based on code from:\n// https://devblogs.nvidia.com/parallelforall/egl-eye-opengl-visualization-without-x-server/\n// https://github.com/facebookresearch/House3D/blob/master/renderer/gl/glContext.cc\n// https://github.com/facebookresearch/habitat-sim\n\n#include <fcntl.h>\n#include <unistd.h>\n\n#include <Corrade/configure.h>\n\n#include <Magnum/Platform/GLContext.h>\n#include <magnum_rendering/rendering_context.hpp>\n#include <util/tiny_logger.hpp>\n\n#if defined(CORRADE_TARGET_APPLE)\n#include <Magnum/Platform/WindowlessCglApplication.h>\n#else\n#include <glad/glad_egl.h>\n#include <Magnum/Platform/WindowlessEglApplication.h>\n#endif\n\nusing namespace Megaverse;\nnamespace Mn = Magnum;\n\n#if !defined(CORRADE_TARGET_APPLE)\n\nconstexpr int MAX_DEVICES = 128;\n\n#define CHECK_EGL_ERROR()                                                      \\\n    do {                                                                       \\\n        EGLint err = eglGetError();                                            \\\n        TCHECK(err == EGL_SUCCESS) << \"EGL error:\" << err;                     \\\n    } while (0)\n\nbool isNvidiaGpuReadable(int device) {\n    const std::string dev = \"/dev/nvidia\" + std::to_string(device);\n    const int retval = open(dev.c_str(), O_RDONLY);\n    if (retval == -1)\n        return false;\n    close(retval);\n    return true;\n}\n\nstruct ContextEGL {\n    explicit ContextEGL(int device)\n        : magnumGlContext_{Mn::NoCreate} {\n        const auto loadStatus = gladLoadEGL();\n        TCHECK(loadStatus) << \"Failed to load EGL \" << loadStatus;\n\n        static const EGLint configAttribs[] = {\n            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE,\n            EGL_OPENGL_BIT, EGL_NONE};\n\n        // 1. Initialize EGL\n        {\n            EGLDeviceEXT eglDevices[MAX_DEVICES];\n            EGLint numDevices;\n            eglQueryDevicesEXT(MAX_DEVICES, eglDevices, &numDevices);\n            CHECK_EGL_ERROR();\n\n            TCHECK(numDevices > 0) << \"[EGL] No devices detected\";\n            TLOG(INFO) << \"[EGL] Detected \" << numDevices << \" EGL devices\";\n\n            int eglDevId;\n            for (eglDevId = 0; eglDevId < numDevices; ++eglDevId) {\n                EGLAttrib cudaDevNumber;\n\n                if (eglQueryDeviceAttribEXT(eglDevices[eglDevId],\n                                            EGL_CUDA_DEVICE_NV,\n                                            &cudaDevNumber) == EGL_FALSE)\n                    continue;\n\n                if (cudaDevNumber == device)\n                    break;\n            }\n\n            TCHECK(eglDevId < numDevices)\n                << \"[EGL] Could not find an EGL device for CUDA device \"\n                << device;\n\n            TCHECK(isNvidiaGpuReadable(eglDevId))\n                << \"[EGL] EGL device \" << eglDevId << \", CUDA device \" << device\n                << \" is not readable\";\n\n            TLOG(INFO) << \"[EGL] Selected EGL device \" << eglDevId\n                       << \" for CUDA device \" << device;\n            display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT,\n                                                eglDevices[eglDevId], nullptr);\n            CHECK_EGL_ERROR();\n        }\n\n        EGLint major, minor;\n        EGLBoolean retval = eglInitialize(display_, &major, &minor);\n        if (!retval) {\n            TLOG(ERROR) << \"[EGL] Failed to initialize.\";\n        }\n        CHECK_EGL_ERROR();\n\n        TLOG(INFO) << \"[EGL] Version: \" << eglQueryString(display_, EGL_VERSION)\n                   << \" display: \" << display_;\n        TLOG(INFO) << \"[EGL] Vendor: \" << eglQueryString(display_, EGL_VENDOR);\n\n        // 2. Select an appropriate configuration\n        EGLint numConfigs;\n        EGLConfig eglConfig;\n        eglChooseConfig(display_, configAttribs, &eglConfig, 1, &numConfigs);\n        if (numConfigs != 1) {\n            TLOG(ERROR) << \"[EGL] Cannot create EGL config. Your driver may \"\n                           \"not support EGL.\";\n        }\n        CHECK_EGL_ERROR();\n\n        // 3. Bind the API\n        retval = eglBindAPI(EGL_OPENGL_API);\n        if (!retval) {\n            TLOG(ERROR) << \"[EGL] failed to bind OpenGL API\";\n        }\n        CHECK_EGL_ERROR();\n\n        // 4. Create a context\n        context_ = eglCreateContext(display_, eglConfig, EGL_NO_CONTEXT, NULL);\n        CHECK_EGL_ERROR();\n\n        // 5. Make context current and create Magnum context\n        makeCurrent(false);\n\n        TCHECK(magnumGlContext_.tryCreate())\n            << \"[EGL] Failed to create OpenGL context\";\n        isValid_ = true;\n    };\n\n    void makeCurrent(bool updateMagnumContext = true) {\n        if (Magnum::GL::Context::hasCurrent())\n            Magnum::GL::Context::makeCurrent(nullptr);\n\n        EGLBoolean retval =\n            eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, context_);\n        if (!retval)\n            TLOG(ERROR) << \"[EGL] Failed to make EGL context current\";\n        CHECK_EGL_ERROR();\n\n        if (updateMagnumContext)\n            magnumGlContext_.makeCurrent(&magnumGlContext_);\n    };\n\n    bool isValid() { return isValid_; };\n\n    ~ContextEGL() {\n        eglDestroyContext(display_, context_);\n        //        eglTerminate(display_);\n\n        Magnum::GL::Context::makeCurrent(nullptr);\n    }\n\n  private:\n    EGLDisplay display_;\n    EGLContext context_;\n    Mn::Platform::GLContext magnumGlContext_;\n    bool isValid_ = false;\n};\n\nstruct WindowlessContext::Impl {\n    explicit Impl(int device) {\n        TLOG(INFO);\n        glContext = std::make_unique<ContextEGL>(device);\n        makeCurrent();\n    }\n\n    void makeCurrent() { glContext->makeCurrent(); }\n\n    std::unique_ptr<ContextEGL> glContext{nullptr};\n};\n\n#else\n\nstruct WindowlessContext::Impl {\n    explicit Impl(int device)\n        : magnumGLContext_{Mn::NoCreate}, windowlessGLContext_{Mn::NoCreate} {\n        TLOG(INFO);\n        if (device != 0)\n            TLOG(ERROR) << \"Context does not support device specification\";\n        Mn::Platform::WindowlessGLContext::Configuration config;\n        windowlessGLContext_ =\n            Mn::Platform::WindowlessGLContext{config, &magnumGLContext_};\n        if (!windowlessGLContext_.isCreated())\n            TLOG(ERROR) << \"Unable to create windowless context\";\n        makeCurrent(false);\n\n        if (!magnumGLContext_.tryCreate())\n            TLOG(ERROR) << \"Unable to create OpenGL context\";\n    }\n\n    void makeCurrent(bool updateMagnumContext = true) {\n        if (Magnum::GL::Context::hasCurrent())\n            Magnum::GL::Context::makeCurrent(nullptr);\n\n        windowlessGLContext_.makeCurrent();\n\n        if (updateMagnumContext)\n            magnumGLContext_.makeCurrent(&magnumGLContext_);\n    };\n\n    Mn::Platform::GLContext magnumGLContext_;\n    Mn::Platform::WindowlessGLContext windowlessGLContext_;\n};\n\n#endif\n\nWindowlessContext::WindowlessContext(int device /* = 0 */)\n    : pimpl{std::make_unique<WindowlessContext::Impl>(device)} {}\n\nWindowlessContext::~WindowlessContext() = default;\n\nvoid WindowlessContext::makeCurrent() { pimpl->makeCurrent(); }\n"
  },
  {
    "path": "src/libs/mazes/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(libmazes VERSION 0.1 LANGUAGES CXX)\n\nadd_library_default(mazes)\ntarget_link_libraries(mazes PUBLIC util)\n"
  },
  {
    "path": "src/libs/mazes/LICENSE.txt",
    "content": "Copyright (c) 2017 Raziman T. V.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "src/libs/mazes/Readme.md",
    "content": "# Maze generator\n\n**Generate mazes of different shapes and arbitrary sizes**\n![Maze types](/examples/mazes.png \"Maze types\")\n\nMaze generator can create rectangular, hexagonal, honeycomb and circular mazes.\nMaze generation can be done using Kruskal's algorithm, depth-first search,\nbreadth-first search, loop-erased random walk or Prim's algorithm. Mazes can be\nrendered in svg or png format (using gnuplot as intermediate in the latter\ncase).\n\n## Dependencies\n\nMaze generator uses gnuplot (with a system call `gnuplot`) to render png mazes.\nSo make sure that `gnuplot 5.0+` is installed with `pngcairo` terminal support\nand is in the path if you wish to use png.\n\nThe code is written in C++ 11, you will need a not-too-ancient C++ compiler to\nbuild it.\n\n## Installation\n\n```\ncd src; make\n```\n\n## Usage\n\n```\nUsage: mazegen [--help] [-m <maze type>] [-a <algorithm type>]\n               [-s <size> | -w <width> -h <height>]\n               [-t <output type] [-o <output prefix>]\n\nOptional arguments\n  --help  Show this message and exit\n  -m      Maze type\n          0: Rectangular (default)\n          1: Hexagonal (triangular lattice)\n          2: Honeycomb\n          3: Circular\n          4: Circular (triangular lattice)\n          5: User-defined\n  -a      Algorithm type\n          0: Kruskal's algorithm (default)\n          1: Depth-first search\n          2: Breadth-first search\n          3: Loop-erased random walk\n          4: Prim's algorithm\n  -s      Size (non-rectangular mazes, default: 20)\n  -w,-h   Width and height (rectangular maze, default: 20)\n  -t      Output type\n          0: svg output (default)\n          1: png output using gnuplot (.plt) intermediate \n  -o      Prefix for .svg, .plt and .png outputs (default: maze)\n```\n\n## Issues\n\nThe arcs in the circular mazes are plotted as parametric curves in gnuplot, and\npng can take quite long to render for large mazes.\n"
  },
  {
    "path": "src/libs/mazes/examples/gen.sh",
    "content": "#!/bin/bash\n\n../src/mazegen -m 0 -w 40 -h 40 -a 2 -t 1 -o rectangular_BFS\n../src/mazegen -m 1 -s 20 -a 0 -t 0 -o hexagonal_Kruskal\n../src/mazegen -m 2 -s 20 -a 3 -t 1 -o honeycomb_LERW\n../src/mazegen -m 3 -s 20 -a 1 -t 0 -o circular_DFS\n../src/mazegen -m 4 -s 20 -a 0 -o circularhexagon_Kruskal\n../src/mazegen -m 5 -a 4 -f manual_input.xy -o manual_Prim\n\n"
  },
  {
    "path": "src/libs/mazes/examples/manual_input.xy",
    "content": "1001\n0 65 Line 4.66667 1.33333 5.33333 1.33333\n0 153 Line 5.33333 1.33333 6 1.33333\n0 252 Line 4.66667 1.33333 4.66667 2\n0 684 Line 4.66667 2 5.33333 2\n0 685 Line 5.33333 2 6 2\n0 761 Line 6 1.33333 6 2\n1 128 Line 18 5.33333 18.6667 5.33333\n1 300 Line 18.6667 6 19.3333 6\n1 488 Line 18 5.33333 18 6\n1 674 Line 18.6667 5.33333 19.3333 5.33333\n1 897 Line 18 6 18.6667 6\n1 969 Line 19.3333 5.33333 19.3333 6\n2 28 Line 21.3333 16.6667 21.3333 17.3333\n2 120 Line 19.3333 17.3333 21.3333 17.3333\n2 218 Line 20.6667 16.6667 21.3333 16.6667\n2 641 Line 19.3333 16.6667 20 16.6667\n2 697 Line 20 16.6667 20.6667 16.6667\n2 929 Line 19.3333 16.6667 19.3333 17.3333\n3 66 Line 6.66667 14 6.66667 14.6667\n3 99 Line 6.66667 14.6667 7.33333 14.6667\n3 222 Line 7.33333 13.3333 7.33333 14.6667\n3 728 Line 6.66667 13.3333 7.33333 13.3333\n3 784 Line 6.66667 13.3333 6.66667 14\n4 25 Line 6 7.33333 6 8\n4 60 Line 6 8 6 8.66667\n4 269 Line 4.66667 7.33333 6 7.33333\n4 747 Line 4.66667 8.66667 5.33333 8.66667\n4 748 Line 5.33333 8.66667 6 8.66667\n4 852 Line 4.66667 7.33333 4.66667 8\n4 853 Line 4.66667 8 4.66667 8.66667\n5 52 Line 28.6667 5.33333 29.3333 5.33333\n5 56 Line 29.3333 6 30 6\n5 520 Line 28.6667 6 29.3333 6\n5 564 Line 28.6667 5.33333 28.6667 6\n5 583 Line 30 5.33333 30 6\n5 886 Line 29.3333 5.33333 30 5.33333\n6 82 Line 12 10.6667 12 11.3333\n6 93 Line 12 11.3333 13.3333 11.3333\n6 284 Line 13.3333 10.6667 13.3333 11.3333\n6 936 Line 12 10.6667 12.6667 10.6667\n6 947 Line 12.6667 10.6667 13.3333 10.6667\n7 445 Line 12 2 12 2.66667\n7 489 Line 10.6667 2.66667 11.3333 2.66667\n7 523 Line 10.6667 2 10.6667 2.66667\n7 554 Line 11.3333 2.66667 12 2.66667\n7 688 Line 11.3333 2 12 2\n7 742 Line 10.6667 2 11.3333 2\n8 22 Line 4 18.6667 4 20.6667\n8 94 Line 2.66667 20.6667 4 20.6667\n8 154 Line 2.66667 18.6667 4 18.6667\n8 231 Line 2.66667 18.6667 2.66667 20\n8 981 Line 2.66667 20 2.66667 20.6667\n9 85 Line 31.3333 18 32 18\n9 91 Line 30.6667 16 32 16\n9 104 Line 32 17.3333 32 18\n9 108 Line 30.6667 16.6667 30.6667 18\n9 141 Line 30.6667 16 30.6667 16.6667\n9 228 Line 30.6667 18 31.3333 18\n9 288 Line 32 16 32 17.3333\n10 126 Line 18 10 18.6667 10\n10 289 Line 18 10 18 11.3333\n10 464 Line 18 11.3333 18.6667 11.3333\n10 793 Line 18.6667 10 18.6667 10.6667\n10 794 Line 18.6667 10.6667 18.6667 11.3333\n11 69 Line 10 20.6667 13.3333 20.6667\n11 192 Line 10.6667 21.3333 12.6667 21.3333\n11 215 Line 10 20.6667 10 21.3333\n11 234 Line 10 21.3333 10.6667 21.3333\n11 422 Line 12.6667 21.3333 13.3333 21.3333\n11 443 Line 13.3333 20.6667 13.3333 21.3333\n12 81 Line 0.666667 14 2 14\n12 204 Line 0.666667 14.6667 2.66667 14.6667\n12 292 Line 2.66667 14 2.66667 14.6667\n12 475 Line 0.666667 14 0.666667 14.6667\n12 614 Line 2 14 2.66667 14\n13 188 Line 24.6667 1.33333 24.6667 2.66667\n13 619 Line 25.3333 2 25.3333 2.66667\n13 704 Line 25.3333 1.33333 25.3333 2\n13 760 Line 24.6667 2.66667 25.3333 2.66667\n13 943 Line 24.6667 1.33333 25.3333 1.33333\n14 -1 Line 0 8 0 12\n14 39 Line 0.666667 8 0.666667 9.33333\n14 259 Line 0 12 0.666667 12\n14 293 Line 0.666667 10.6667 0.666667 12\n14 775 Line 0 8 0.666667 8\n14 991 Line 0.666667 9.33333 0.666667 10\n14 992 Line 0.666667 10 0.666667 10.6667\n15 -1 Line 7.33333 22.6667 12.6667 22.6667\n15 192 Line 10.6667 22 12.6667 22\n15 194 Line 7.33333 22 7.33333 22.6667\n15 233 Line 7.33333 22 8.66667 22\n15 234 Line 8.66667 22 10.6667 22\n15 423 Line 12.6667 22 12.6667 22.6667\n16 63 Line 22 14.6667 22.6667 14.6667\n16 150 Line 22 13.3333 22.6667 13.3333\n16 491 Line 22.6667 13.3333 22.6667 14\n16 492 Line 22.6667 14 22.6667 14.6667\n16 627 Line 21.3333 13.3333 21.3333 14\n16 628 Line 21.3333 14 21.3333 14.6667\n16 695 Line 21.3333 14.6667 22 14.6667\n16 773 Line 21.3333 13.3333 22 13.3333\n17 22 Line 4 20.6667 5.33333 20.6667\n17 94 Line 4 20.6667 4 22\n17 155 Line 4 22 5.33333 22\n17 164 Line 5.33333 21.3333 5.33333 22\n17 180 Line 5.33333 20.6667 5.33333 21.3333\n18 31 Line 15.3333 20.6667 16.6667 20.6667\n18 87 Line 17.3333 20 17.3333 20.6667\n18 103 Line 17.3333 19.3333 17.3333 20\n18 127 Line 17.3333 17.3333 17.3333 19.3333\n18 248 Line 15.3333 20 15.3333 20.6667\n18 290 Line 16.6667 20.6667 17.3333 20.6667\n18 296 Line 16 17.3333 17.3333 17.3333\n18 320 Line 15.3333 18 15.3333 18.6667\n18 344 Line 15.3333 18.6667 15.3333 19.3333\n18 356 Line 15.3333 17.3333 15.3333 18\n18 505 Line 15.3333 17.3333 16 17.3333\n18 630 Line 15.3333 19.3333 15.3333 20\n19 22 Line 5.33333 18 5.33333 20.6667\n19 36 Line 6.66667 18 6.66667 20.6667\n19 180 Line 5.33333 20.6667 6.66667 20.6667\n19 585 Line 5.33333 18 6 18\n19 586 Line 6 18 6.66667 18\n20 32 Line 0.666667 18 2 18\n20 98 Line 0.666667 20 2 20\n20 102 Line 0.666667 18 0.666667 20\n20 231 Line 2 18 2 20\n21 148 Line 9.33333 11.3333 9.33333 12\n21 185 Line 10 10.6667 10 12\n21 498 Line 9.33333 12 10 12\n21 960 Line 9.33333 10.6667 9.33333 11.3333\n21 997 Line 9.33333 10.6667 10 10.6667\n22 154 Line 4 18 4 18.6667\n22 230 Line 4 18 5.33333 18\n23 68 Line 4.66667 13.3333 4.66667 14\n23 124 Line 3.33333 14 4.66667 14\n23 292 Line 3.33333 13.3333 3.33333 14\n23 700 Line 3.33333 13.3333 4 13.3333\n23 701 Line 4 13.3333 4.66667 13.3333\n24 322 Line 20 12 20.6667 12\n24 358 Line 20 11.3333 20 12\n24 410 Line 21.3333 11.3333 21.3333 12\n24 458 Line 20 11.3333 20.6667 11.3333\n24 459 Line 20.6667 11.3333 21.3333 11.3333\n24 572 Line 20.6667 12 21.3333 12\n25 60 Line 6 8 6.66667 8\n25 269 Line 6 6.66667 6 7.33333\n25 369 Line 6.66667 6.66667 6.66667 7.33333\n25 665 Line 6.66667 7.33333 6.66667 8\n25 985 Line 6 6.66667 6.66667 6.66667\n26 -1 Line 26.6667 0 28.6667 0\n26 167 Line 26.6667 0 26.6667 0.666667\n26 177 Line 28 0.666667 28.6667 0.666667\n26 631 Line 28.6667 0 28.6667 0.666667\n26 814 Line 26.6667 0.666667 27.3333 0.666667\n26 815 Line 27.3333 0.666667 28 0.666667\n27 74 Line 7.33333 2 8.66667 2\n27 153 Line 6.66667 1.33333 8 1.33333\n27 279 Line 8.66667 1.33333 8.66667 2\n27 303 Line 8 1.33333 8.66667 1.33333\n27 449 Line 6.66667 2 7.33333 2\n27 761 Line 6.66667 1.33333 6.66667 2\n28 120 Line 21.3333 17.3333 21.3333 21.3333\n28 156 Line 22 16.6667 22 18\n28 218 Line 21.3333 16.6667 22 16.6667\n28 271 Line 22 20.6667 22 21.3333\n28 514 Line 22 18 22 18.6667\n28 558 Line 22 18.6667 22 19.3333\n28 872 Line 22 19.3333 22 20\n28 873 Line 22 20 22 20.6667\n28 996 Line 21.3333 21.3333 22 21.3333\n29 91 Line 32 13.3333 32 15.3333\n29 201 Line 32.6667 12 32.6667 13.3333\n29 205 Line 32.6667 13.3333 32.6667 14.6667\n29 229 Line 32 12 32 13.3333\n29 275 Line 32 12 32.6667 12\n29 870 Line 32 15.3333 32.6667 15.3333\n29 891 Line 32.6667 14.6667 32.6667 15.3333\n30 83 Line 13.3333 5.33333 13.3333 6.66667\n30 506 Line 14 5.33333 14 6\n30 541 Line 14 6 14 6.66667\n30 661 Line 13.3333 6.66667 14 6.66667\n30 714 Line 13.3333 5.33333 14 5.33333\n31 -1 Line 15.3333 22.6667 16.6667 22.6667\n31 248 Line 15.3333 20.6667 15.3333 21.3333\n31 287 Line 15.3333 21.3333 15.3333 22.6667\n31 290 Line 16.6667 20.6667 16.6667 22.6667\n32 -1 Line 0 17.3333 0 18\n32 102 Line 0 18 0.666667 18\n32 244 Line 0 17.3333 2 17.3333\n32 690 Line 2 17.3333 2 18\n33 53 Line 32 1.33333 32 2.66667\n33 96 Line 29.3333 1.33333 32 1.33333\n33 161 Line 29.3333 2.66667 32 2.66667\n33 312 Line 29.3333 1.33333 29.3333 2\n33 915 Line 29.3333 2 29.3333 2.66667\n34 239 Line 4 6 5.33333 6\n34 278 Line 5.33333 5.33333 5.33333 6\n34 485 Line 4 5.33333 4.66667 5.33333\n34 486 Line 4.66667 5.33333 5.33333 5.33333\n34 549 Line 4 5.33333 4 6\n35 73 Line 24 6 24.6667 6\n35 209 Line 22.6667 6.66667 24.6667 6.66667\n35 277 Line 24.6667 6 24.6667 6.66667\n35 305 Line 22.6667 6 24 6\n35 789 Line 22.6667 6 22.6667 6.66667\n36 49 Line 6.66667 20.6667 8.66667 20.6667\n36 69 Line 8.66667 18 8.66667 20.6667\n36 893 Line 8 18 8.66667 18\n36 894 Line 6.66667 18 7.33333 18\n36 895 Line 7.33333 18 8 18\n37 384 Line 16 7.33333 16.6667 7.33333\n37 607 Line 16 6 16 6.66667\n37 745 Line 16.6667 6 16.6667 6.66667\n37 746 Line 16.6667 6.66667 16.6667 7.33333\n37 874 Line 16 6.66667 16 7.33333\n37 876 Line 16 6 16.6667 6\n38 39 Line 1.33333 9.33333 2 9.33333\n38 206 Line 2 9.33333 2 10.6667\n38 236 Line 2 10.6667 2 11.3333\n38 293 Line 1.33333 10.6667 1.33333 11.3333\n38 813 Line 1.33333 11.3333 2 11.3333\n38 991 Line 1.33333 9.33333 1.33333 10\n38 992 Line 1.33333 10 1.33333 10.6667\n39 206 Line 2 8.66667 2 9.33333\n39 245 Line 0.666667 7.33333 2 7.33333\n39 596 Line 2 7.33333 2 8\n39 597 Line 2 8 2 8.66667\n39 775 Line 0.666667 7.33333 0.666667 8\n39 991 Line 0.666667 9.33333 1.33333 9.33333\n40 549 Line 3.33333 5.33333 3.33333 6\n40 550 Line 3.33333 6 3.33333 6.66667\n40 634 Line 2.66667 5.33333 3.33333 5.33333\n40 635 Line 2.66667 6.66667 3.33333 6.66667\n40 902 Line 2.66667 5.33333 2.66667 6\n40 903 Line 2.66667 6 2.66667 6.66667\n41 283 Line 16 11.3333 16 12\n41 326 Line 15.3333 13.3333 16 13.3333\n41 388 Line 16 12.6667 16 13.3333\n41 426 Line 15.3333 11.3333 16 11.3333\n41 569 Line 15.3333 12.6667 15.3333 13.3333\n41 738 Line 15.3333 11.3333 15.3333 12\n41 739 Line 15.3333 12 15.3333 12.6667\n41 913 Line 16 12 16 12.6667\n42 -1 Line 0 2.66667 0 5.33333\n42 182 Line 0 5.33333 0.666667 5.33333\n42 598 Line 0 2.66667 0.666667 2.66667\n42 977 Line 0.666667 2.66667 0.666667 3.33333\n42 978 Line 0.666667 3.33333 0.666667 4\n42 979 Line 0.666667 4 0.666667 4.66667\n42 980 Line 0.666667 4.66667 0.666667 5.33333\n43 57 Line 14.6667 7.33333 14.6667 8\n43 272 Line 14.6667 7.33333 15.3333 7.33333\n43 360 Line 14.6667 8.66667 15.3333 8.66667\n43 875 Line 15.3333 7.33333 15.3333 8\n43 905 Line 15.3333 8 15.3333 8.66667\n43 949 Line 14.6667 8 14.6667 8.66667\n44 -1 Line 19.3333 22.6667 20.6667 22.6667\n44 120 Line 19.3333 21.3333 20.6667 21.3333\n44 637 Line 19.3333 22 19.3333 22.6667\n44 795 Line 20.6667 21.3333 20.6667 22\n44 796 Line 20.6667 22 20.6667 22.6667\n44 951 Line 19.3333 21.3333 19.3333 22\n45 105 Line 25.3333 13.3333 26.6667 13.3333\n45 759 Line 25.3333 12.6667 25.3333 13.3333\n45 889 Line 25.3333 12.6667 26 12.6667\n45 890 Line 26 12.6667 26.6667 12.6667\n45 967 Line 26.6667 12.6667 26.6667 13.3333\n46 64 Line 15.3333 4.66667 16 4.66667\n46 232 Line 15.3333 4.66667 15.3333 5.33333\n46 420 Line 15.3333 5.33333 16 5.33333\n46 663 Line 16 4.66667 16.6667 4.66667\n46 677 Line 16.6667 4.66667 16.6667 5.33333\n46 876 Line 16 5.33333 16.6667 5.33333\n47 -1 Line 13.3333 22.6667 14 22.6667\n47 287 Line 14 21.3333 14 22.6667\n47 422 Line 13.3333 21.3333 13.3333 22\n47 423 Line 13.3333 22 13.3333 22.6667\n47 443 Line 13.3333 21.3333 14 21.3333\n48 143 Line 21.3333 8 21.3333 8.66667\n48 146 Line 21.3333 8 22.6667 8\n48 439 Line 22.6667 9.33333 23.3333 9.33333\n48 468 Line 21.3333 9.33333 22 9.33333\n48 469 Line 22 9.33333 22.6667 9.33333\n48 682 Line 23.3333 8 23.3333 8.66667\n48 683 Line 23.3333 8.66667 23.3333 9.33333\n48 812 Line 22.6667 8 23.3333 8\n48 974 Line 21.3333 8.66667 21.3333 9.33333\n49 164 Line 6.66667 21.3333 7.33333 21.3333\n49 180 Line 6.66667 20.6667 6.66667 21.3333\n49 215 Line 8.66667 20.6667 8.66667 21.3333\n49 233 Line 7.33333 21.3333 8.66667 21.3333\n50 92 Line 30 9.33333 30 10\n50 255 Line 30 9.33333 31.3333 9.33333\n50 652 Line 31.3333 9.33333 31.3333 10\n50 920 Line 30.6667 10 31.3333 10\n50 937 Line 30 10 30.6667 10\n51 -1 Line 0 20.6667 0 21.3333\n51 98 Line 0.666667 20.6667 1.33333 20.6667\n51 159 Line 1.33333 20.6667 1.33333 21.3333\n51 173 Line 0 21.3333 1.33333 21.3333\n51 907 Line 0 20.6667 0.666667 20.6667\n52 298 Line 28.6667 4 28.6667 5.33333\n52 818 Line 28.6667 3.33333 28.6667 4\n52 843 Line 29.3333 3.33333 29.3333 4\n52 885 Line 29.3333 4 29.3333 4.66667\n52 886 Line 29.3333 4.66667 29.3333 5.33333\n52 916 Line 28.6667 3.33333 29.3333 3.33333\n53 -1 Line 34 0 34 2.66667\n53 -1 Line 32 0 34 0\n53 96 Line 32 0 32 1.33333\n53 161 Line 32 2.66667 34 2.66667\n54 621 Line 13.3333 8.66667 13.3333 9.33333\n54 726 Line 12 8.66667 12 9.33333\n54 780 Line 12 8.66667 12.6667 8.66667\n54 781 Line 12.6667 8.66667 13.3333 8.66667\n54 935 Line 12 9.33333 12.6667 9.33333\n54 946 Line 12.6667 9.33333 13.3333 9.33333\n55 62 Line 10.6667 13.3333 11.3333 13.3333\n55 339 Line 10.6667 14 11.3333 14\n55 502 Line 11.3333 13.3333 12 13.3333\n55 605 Line 11.3333 14 12 14\n55 811 Line 12 13.3333 12 14\n55 955 Line 10.6667 13.3333 10.6667 14\n56 121 Line 30.6667 6 30.6667 7.33333\n56 520 Line 29.3333 6 29.3333 6.66667\n56 521 Line 29.3333 6.66667 29.3333 7.33333\n56 583 Line 30 6 30.6667 6\n56 622 Line 29.3333 7.33333 30 7.33333\n56 623 Line 30 7.33333 30.6667 7.33333\n57 272 Line 14.6667 6.66667 14.6667 7.33333\n57 438 Line 14 7.33333 14 8\n57 541 Line 14 6.66667 14.6667 6.66667\n57 661 Line 14 6.66667 14 7.33333\n57 949 Line 14 8 14.6667 8\n58 127 Line 17.3333 17.3333 18.6667 17.3333\n58 238 Line 17.3333 16.6667 18 16.6667\n58 253 Line 18 16.6667 18.6667 16.6667\n58 296 Line 17.3333 16.6667 17.3333 17.3333\n58 929 Line 18.6667 16.6667 18.6667 17.3333\n59 140 Line 28 21.3333 28.6667 21.3333\n59 171 Line 29.3333 20.6667 29.3333 21.3333\n59 225 Line 28 19.3333 28 20\n59 242 Line 28 19.3333 29.3333 19.3333\n59 247 Line 29.3333 19.3333 29.3333 20.6667\n59 257 Line 28 20 28 21.3333\n59 304 Line 28.6667 21.3333 29.3333 21.3333\n60 589 Line 6.66667 8.66667 6.66667 9.33333\n60 601 Line 6.66667 8 6.66667 8.66667\n60 617 Line 6 9.33333 6.66667 9.33333\n60 748 Line 6 8.66667 6 9.33333\n61 405 Line 18 12.6667 18.6667 12.6667\n61 446 Line 18.6667 12.6667 18.6667 13.3333\n61 447 Line 18.6667 13.3333 18.6667 14\n61 466 Line 18 14 18.6667 14\n61 577 Line 18 12.6667 18 13.3333\n61 578 Line 18 13.3333 18 14\n62 107 Line 10.6667 12.6667 11.3333 12.6667\n62 144 Line 9.33333 13.3333 10 13.3333\n62 321 Line 9.33333 12.6667 9.33333 13.3333\n62 498 Line 9.33333 12.6667 10 12.6667\n62 502 Line 11.3333 12.6667 11.3333 13.3333\n62 774 Line 10 12.6667 10.6667 12.6667\n62 955 Line 10 13.3333 10.6667 13.3333\n63 156 Line 22 16 22.6667 16\n63 695 Line 22 14.6667 22 15.3333\n63 696 Line 22 15.3333 22 16\n63 849 Line 22.6667 14.6667 22.6667 15.3333\n63 850 Line 22.6667 15.3333 22.6667 16\n64 232 Line 15.3333 4 15.3333 4.66667\n64 494 Line 15.3333 3.33333 15.3333 4\n64 610 Line 15.3333 3.33333 16 3.33333\n64 662 Line 16 3.33333 16 4\n64 663 Line 16 4 16 4.66667\n65 -1 Line 4.66667 0 5.33333 0\n65 153 Line 5.33333 0.666667 5.33333 1.33333\n65 165 Line 5.33333 0 5.33333 0.666667\n65 993 Line 4.66667 0 4.66667 0.666667\n65 994 Line 4.66667 0.666667 4.66667 1.33333\n66 68 Line 4.66667 14 6 14\n66 99 Line 5.33333 14.6667 6.66667 14.6667\n66 124 Line 4.66667 14 4.66667 14.6667\n66 286 Line 4.66667 14.6667 5.33333 14.6667\n66 784 Line 6 14 6.66667 14\n67 86 Line 26.6667 4 27.3333 4\n67 113 Line 28 2 28 3.33333\n67 177 Line 28 1.33333 28 2\n67 507 Line 27.3333 4 28 4\n67 576 Line 26.6667 2.66667 26.6667 3.33333\n67 814 Line 26.6667 1.33333 27.3333 1.33333\n67 815 Line 27.3333 1.33333 28 1.33333\n67 818 Line 28 3.33333 28 4\n67 821 Line 26.6667 3.33333 26.6667 4\n67 961 Line 26.6667 1.33333 26.6667 2\n67 962 Line 26.6667 2 26.6667 2.66667\n68 112 Line 4.66667 13.3333 6 13.3333\n68 784 Line 6 13.3333 6 14\n69 134 Line 9.33333 17.3333 13.3333 17.3333\n69 215 Line 8.66667 20.6667 10 20.6667\n69 221 Line 13.3333 17.3333 13.3333 19.3333\n69 323 Line 8.66667 17.3333 9.33333 17.3333\n69 331 Line 13.3333 20 13.3333 20.6667\n69 537 Line 13.3333 19.3333 13.3333 20\n69 893 Line 8.66667 17.3333 8.66667 18\n70 99 Line 5.33333 16 6.66667 16\n70 176 Line 5.33333 16.6667 6.66667 16.6667\n70 529 Line 5.33333 16 5.33333 16.6667\n70 792 Line 6.66667 16 6.66667 16.6667\n71 144 Line 9.33333 14.6667 10 14.6667\n71 168 Line 9.33333 14.6667 9.33333 15.3333\n71 340 Line 9.33333 15.3333 10 15.3333\n71 394 Line 10.6667 14.6667 10.6667 15.3333\n71 544 Line 10 15.3333 10.6667 15.3333\n71 956 Line 10 14.6667 10.6667 14.6667\n72 -1 Line 20.6667 0 21.3333 0\n72 202 Line 20.6667 0 20.6667 3.33333\n72 246 Line 21.3333 2.66667 21.3333 3.33333\n72 249 Line 21.3333 0 21.3333 2.66667\n72 941 Line 20.6667 3.33333 21.3333 3.33333\n73 277 Line 24.6667 6 26 6\n73 305 Line 24 5.33333 24 6\n73 361 Line 26 6 26.6667 6\n73 451 Line 26.6667 5.33333 26.6667 6\n73 798 Line 24.6667 5.33333 25.3333 5.33333\n73 803 Line 25.3333 5.33333 26 5.33333\n73 804 Line 26 5.33333 26.6667 5.33333\n73 857 Line 24 5.33333 24.6667 5.33333\n74 213 Line 8.66667 2 8.66667 2.66667\n74 449 Line 7.33333 2 7.33333 2.66667\n74 522 Line 7.33333 2.66667 8 2.66667\n74 787 Line 8 2.66667 8.66667 2.66667\n75 225 Line 26 20 27.3333 20\n75 256 Line 26 21.3333 27.3333 21.3333\n75 257 Line 27.3333 20 27.3333 21.3333\n75 299 Line 26 20 26 21.3333\n76 371 Line 19.3333 14 20 14\n76 447 Line 18.6667 14 19.3333 14\n76 466 Line 18.6667 14 18.6667 14.6667\n76 628 Line 20.6667 14 20.6667 14.6667\n76 670 Line 20 14 20.6667 14\n76 901 Line 18.6667 14.6667 19.3333 14.6667\n76 918 Line 19.3333 14.6667 20 14.6667\n76 944 Line 20 14.6667 20.6667 14.6667\n77 -1 Line 0 0 1.33333 0\n77 130 Line 1.33333 0 1.33333 0.666667\n77 261 Line 0 0.666667 1.33333 0.666667\n78 126 Line 18.6667 8.66667 18.6667 10\n78 175 Line 19.3333 8.66667 19.3333 9.33333\n78 793 Line 18.6667 10 19.3333 10\n78 810 Line 18.6667 8.66667 19.3333 8.66667\n78 982 Line 19.3333 9.33333 19.3333 10\n79 212 Line 24 18.6667 24 20\n79 271 Line 22.6667 20.6667 24 20.6667\n79 477 Line 22.6667 18.6667 23.3333 18.6667\n79 478 Line 23.3333 18.6667 24 18.6667\n79 558 Line 22.6667 18.6667 22.6667 19.3333\n79 869 Line 24 20 24 20.6667\n79 872 Line 22.6667 19.3333 22.6667 20\n79 873 Line 22.6667 20 22.6667 20.6667\n80 -1 Line 34 3.33333 34 4\n80 161 Line 31.3333 3.33333 34 3.33333\n80 315 Line 31.3333 3.33333 31.3333 4\n80 790 Line 33.3333 4 34 4\n80 839 Line 32.6667 4 33.3333 4\n80 854 Line 31.3333 4 32 4\n80 855 Line 32 4 32.6667 4\n81 -1 Line 0 13.3333 0 14\n81 259 Line 0 13.3333 0.666667 13.3333\n81 475 Line 0 14 0.666667 14\n81 614 Line 2 13.3333 2 14\n81 776 Line 0.666667 13.3333 1.33333 13.3333\n81 777 Line 1.33333 13.3333 2 13.3333\n82 185 Line 10.6667 10.6667 10.6667 11.3333\n82 841 Line 10.6667 10.6667 11.3333 10.6667\n82 842 Line 11.3333 10.6667 12 10.6667\n82 999 Line 10.6667 11.3333 11.3333 11.3333\n82 1000 Line 11.3333 11.3333 12 11.3333\n83 324 Line 12.6667 7.33333 13.3333 7.33333\n83 401 Line 12.6667 6.66667 12.6667 7.33333\n83 418 Line 12.6667 5.33333 13.3333 5.33333\n83 524 Line 12.6667 5.33333 12.6667 6\n83 525 Line 12.6667 6 12.6667 6.66667\n83 661 Line 13.3333 6.66667 13.3333 7.33333\n84 255 Line 29.3333 8.66667 30.6667 8.66667\n84 295 Line 30.6667 8 30.6667 8.66667\n84 516 Line 29.3333 8 29.3333 8.66667\n84 622 Line 29.3333 8 30 8\n84 623 Line 30 8 30.6667 8\n85 104 Line 32 18 33.3333 18\n85 191 Line 33.3333 18 33.3333 19.3333\n85 211 Line 32 19.3333 33.3333 19.3333\n85 224 Line 31.3333 19.3333 32 19.3333\n85 228 Line 31.3333 18 31.3333 19.3333\n86 451 Line 26.6667 5.33333 27.3333 5.33333\n86 507 Line 27.3333 4 27.3333 4.66667\n86 508 Line 27.3333 4.66667 27.3333 5.33333\n86 804 Line 26.6667 4.66667 26.6667 5.33333\n86 822 Line 26.6667 4 26.6667 4.66667\n87 -1 Line 17.3333 22.6667 18.6667 22.6667\n87 103 Line 17.3333 20 18.6667 20\n87 280 Line 18.6667 20 18.6667 20.6667\n87 290 Line 17.3333 20.6667 17.3333 22.6667\n87 637 Line 18.6667 22 18.6667 22.6667\n87 950 Line 18.6667 20.6667 18.6667 21.3333\n87 951 Line 18.6667 21.3333 18.6667 22\n88 -1 Line 34 5.33333 34 6.66667\n88 170 Line 33.3333 5.33333 33.3333 6.66667\n88 536 Line 33.3333 6.66667 34 6.66667\n88 791 Line 33.3333 5.33333 34 5.33333\n89 725 Line 10.6667 9.33333 11.3333 9.33333\n89 726 Line 11.3333 9.33333 12 9.33333\n89 740 Line 10.6667 9.33333 10.6667 10\n89 841 Line 10.6667 10 11.3333 10\n89 842 Line 11.3333 10 12 10\n89 935 Line 12 9.33333 12 10\n90 -1 Line 17.3333 0 19.3333 0\n90 151 Line 19.3333 0 19.3333 1.33333\n90 162 Line 17.3333 1.33333 18.6667 1.33333\n90 254 Line 18.6667 1.33333 19.3333 1.33333\n90 723 Line 17.3333 0 17.3333 0.666667\n90 724 Line 17.3333 0.666667 17.3333 1.33333\n91 118 Line 30 14 30 16\n91 131 Line 30 13.3333 30 14\n91 135 Line 30 13.3333 30.6667 13.3333\n91 141 Line 30 16 30.6667 16\n91 229 Line 30.6667 13.3333 32 13.3333\n91 870 Line 32 15.3333 32 16\n92 220 Line 28.6667 10.6667 28.6667 11.3333\n92 255 Line 29.3333 9.33333 30 9.33333\n92 644 Line 28.6667 9.33333 28.6667 10\n92 825 Line 28.6667 11.3333 29.3333 11.3333\n92 826 Line 29.3333 11.3333 30 11.3333\n92 904 Line 28.6667 10 28.6667 10.6667\n92 917 Line 28.6667 9.33333 29.3333 9.33333\n92 937 Line 30 10 30 10.6667\n92 938 Line 30 10.6667 30 11.3333\n93 553 Line 13.3333 11.3333 13.3333 12\n93 608 Line 12 12 12.6667 12\n93 609 Line 12.6667 12 13.3333 12\n93 1000 Line 12 11.3333 12 12\n94 216 Line 2.66667 20.6667 2.66667 22\n94 219 Line 2.66667 22 4 22\n95 138 Line 2.66667 1.33333 2.66667 2.66667\n95 152 Line 3.33333 2.66667 3.33333 3.33333\n95 187 Line 2.66667 3.33333 3.33333 3.33333\n95 252 Line 3.33333 1.33333 3.33333 2\n95 268 Line 3.33333 0.666667 3.33333 1.33333\n95 274 Line 2.66667 0.666667 2.66667 1.33333\n95 281 Line 2.66667 2.66667 2.66667 3.33333\n95 624 Line 2.66667 0.666667 3.33333 0.666667\n95 686 Line 3.33333 2 3.33333 2.66667\n96 -1 Line 29.3333 0 32 0\n96 312 Line 29.3333 0.666667 29.3333 1.33333\n96 631 Line 29.3333 0 29.3333 0.666667\n97 254 Line 18.6667 4 19.3333 4\n97 674 Line 18.6667 4.66667 19.3333 4.66667\n97 675 Line 19.3333 4.66667 20 4.66667\n97 809 Line 18.6667 4 18.6667 4.66667\n97 837 Line 20 4 20 4.66667\n97 948 Line 19.3333 4 20 4\n98 159 Line 1.33333 20.6667 2 20.6667\n98 907 Line 0.666667 20 0.666667 20.6667\n98 981 Line 2 20 2 20.6667\n99 210 Line 7.33333 15.3333 7.33333 16\n99 286 Line 5.33333 14.6667 5.33333 16\n99 309 Line 7.33333 14.6667 7.33333 15.3333\n99 792 Line 6.66667 16 7.33333 16\n100 -1 Line 34 7.33333 34 8.66667\n100 183 Line 33.3333 8.66667 34 8.66667\n100 536 Line 33.3333 7.33333 34 7.33333\n100 971 Line 33.3333 7.33333 33.3333 8\n100 972 Line 33.3333 8 33.3333 8.66667\n101 151 Line 19.3333 1.33333 20 1.33333\n101 202 Line 20 1.33333 20 3.33333\n101 254 Line 19.3333 1.33333 19.3333 3.33333\n101 948 Line 19.3333 3.33333 20 3.33333\n102 -1 Line 0 18 0 20\n102 907 Line 0 20 0.666667 20\n103 127 Line 17.3333 19.3333 18.6667 19.3333\n103 280 Line 18.6667 19.3333 18.6667 20\n104 -1 Line 34 17.3333 34 18\n104 139 Line 33.3333 17.3333 34 17.3333\n104 186 Line 32.6667 17.3333 33.3333 17.3333\n104 191 Line 33.3333 18 34 18\n104 288 Line 32 17.3333 32.6667 17.3333\n105 208 Line 26.6667 13.3333 26.6667 14\n105 763 Line 26 14 26.6667 14\n105 765 Line 25.3333 14 26 14\n105 848 Line 25.3333 13.3333 25.3333 14\n106 117 Line 10 0.666667 11.3333 0.666667\n106 279 Line 10 1.33333 10.6667 1.33333\n106 303 Line 10 0.666667 10 1.33333\n106 402 Line 11.3333 0.666667 11.3333 1.33333\n106 742 Line 10.6667 1.33333 11.3333 1.33333\n107 502 Line 11.3333 12.6667 12 12.6667\n107 608 Line 12 12 12 12.6667\n107 774 Line 10.6667 12 10.6667 12.6667\n107 999 Line 10.6667 12 11.3333 12\n107 1000 Line 11.3333 12 12 12\n108 141 Line 29.3333 16.6667 30.6667 16.6667\n108 207 Line 29.3333 16.6667 29.3333 17.3333\n108 228 Line 30.6667 18 30.6667 19.3333\n108 242 Line 29.3333 17.3333 29.3333 19.3333\n108 247 Line 29.3333 19.3333 30 19.3333\n108 276 Line 30 19.3333 30.6667 19.3333\n109 587 Line 7.33333 4.66667 8 4.66667\n109 588 Line 8 4.66667 8.66667 4.66667\n109 646 Line 8.66667 4 8.66667 4.66667\n109 816 Line 7.33333 4 8 4\n109 817 Line 8 4 8.66667 4\n109 831 Line 7.33333 4 7.33333 4.66667\n110 114 Line 28 14.6667 28 16\n110 208 Line 26.6667 14.6667 27.3333 14.6667\n110 264 Line 26.6667 16 27.3333 16\n110 266 Line 27.3333 14.6667 28 14.6667\n110 270 Line 27.3333 16 28 16\n110 313 Line 26.6667 14.6667 26.6667 16\n111 -1 Line 0 22 0 22.6667\n111 -1 Line 0 22.6667 1.33333 22.6667\n111 145 Line 1.33333 22 1.33333 22.6667\n111 173 Line 0 22 1.33333 22\n112 237 Line 4.66667 12.6667 5.33333 12.6667\n112 479 Line 5.33333 12.6667 6 12.6667\n112 701 Line 4.66667 12.6667 4.66667 13.3333\n112 727 Line 6 12.6667 6 13.3333\n113 177 Line 28 2 28.6667 2\n113 818 Line 28 3.33333 28.6667 3.33333\n113 915 Line 28.6667 2 28.6667 2.66667\n113 916 Line 28.6667 2.66667 28.6667 3.33333\n114 118 Line 28.6667 14 28.6667 16\n114 131 Line 28 14 28.6667 14\n114 207 Line 28 16 28.6667 16\n114 266 Line 28 14 28 14.6667\n115 122 Line 22 2.66667 22.6667 2.66667\n115 188 Line 22.6667 2.66667 24 2.66667\n115 217 Line 22 4.66667 22.6667 4.66667\n115 246 Line 22 2.66667 22 4\n115 307 Line 24 2.66667 24 4\n115 856 Line 23.3333 4.66667 24 4.66667\n115 858 Line 24 4 24 4.66667\n115 954 Line 22 4 22 4.66667\n115 984 Line 22.6667 4.66667 23.3333 4.66667\n116 237 Line 4 12 5.33333 12\n116 435 Line 5.33333 11.3333 5.33333 12\n116 574 Line 4 11.3333 4.66667 11.3333\n116 575 Line 4.66667 11.3333 5.33333 11.3333\n116 805 Line 4 11.3333 4 12\n117 -1 Line 10 0 11.3333 0\n117 165 Line 10 0 10 0.666667\n117 715 Line 11.3333 0 11.3333 0.666667\n118 131 Line 28.6667 14 30 14\n118 141 Line 29.3333 16 30 16\n118 207 Line 28.6667 16 29.3333 16\n119 329 Line 22.6667 10.6667 22.6667 11.3333\n119 330 Line 22.6667 11.3333 22.6667 12\n119 333 Line 22.6667 10.6667 23.3333 10.6667\n119 470 Line 23.3333 10.6667 24 10.6667\n119 638 Line 22.6667 12 23.3333 12\n119 878 Line 24 10.6667 24 11.3333\n119 879 Line 24 11.3333 24 12\n119 986 Line 23.3333 12 24 12\n120 258 Line 19.3333 17.3333 19.3333 19.3333\n120 280 Line 19.3333 19.3333 19.3333 20.6667\n120 795 Line 20.6667 21.3333 21.3333 21.3333\n120 950 Line 19.3333 20.6667 19.3333 21.3333\n121 129 Line 31.3333 6 31.3333 7.33333\n121 295 Line 30.6667 7.33333 31.3333 7.33333\n121 584 Line 30.6667 6 31.3333 6\n122 188 Line 22.6667 1.33333 22.6667 2.66667\n122 249 Line 22 1.33333 22 2.66667\n122 314 Line 22 1.33333 22.6667 1.33333\n123 -1 Line 29.3333 22.6667 30.6667 22.6667\n123 171 Line 29.3333 21.3333 30.6667 21.3333\n123 304 Line 29.3333 21.3333 29.3333 22.6667\n123 311 Line 30.6667 21.3333 30.6667 22.6667\n124 195 Line 3.33333 15.3333 4.66667 15.3333\n124 286 Line 4.66667 14.6667 4.66667 15.3333\n124 292 Line 3.33333 14 3.33333 14.6667\n124 737 Line 3.33333 14.6667 3.33333 15.3333\n125 328 Line 27.3333 6 28 6\n125 363 Line 27.3333 7.33333 28 7.33333\n125 428 Line 27.3333 6 27.3333 6.66667\n125 429 Line 27.3333 6.66667 27.3333 7.33333\n125 495 Line 28 6 28 6.66667\n125 496 Line 28 6.66667 28 7.33333\n126 172 Line 18 8 18 9.33333\n126 810 Line 18.6667 8 18.6667 8.66667\n126 896 Line 18 8 18.6667 8\n126 998 Line 18 9.33333 18 10\n127 258 Line 18.6667 17.3333 18.6667 19.3333\n128 488 Line 17.3333 5.33333 18 5.33333\n128 674 Line 18.6667 4.66667 18.6667 5.33333\n128 677 Line 17.3333 4.66667 17.3333 5.33333\n128 808 Line 17.3333 4.66667 18 4.66667\n128 809 Line 18 4.66667 18.6667 4.66667\n129 163 Line 32 6.66667 32 8.66667\n129 255 Line 31.3333 8.66667 31.3333 9.33333\n129 260 Line 32 5.33333 32 6.66667\n129 295 Line 31.3333 7.33333 31.3333 8.66667\n129 302 Line 31.3333 5.33333 32 5.33333\n129 584 Line 31.3333 5.33333 31.3333 6\n129 652 Line 31.3333 9.33333 32 9.33333\n129 888 Line 32 8.66667 32 9.33333\n130 -1 Line 1.33333 0 2.66667 0\n130 274 Line 1.33333 0.666667 2.66667 0.666667\n130 624 Line 2.66667 0 2.66667 0.666667\n131 160 Line 28 13.3333 29.3333 13.3333\n131 266 Line 28 13.3333 28 14\n131 717 Line 29.3333 13.3333 30 13.3333\n132 157 Line 0.666667 15.3333 0.666667 16\n132 204 Line 0.666667 15.3333 2.66667 15.3333\n132 241 Line 1.33333 16 2.66667 16\n132 467 Line 2.66667 15.3333 2.66667 16\n132 711 Line 0.666667 16 1.33333 16\n133 353 Line 7.33333 12 8 12\n133 461 Line 6.66667 11.3333 6.66667 12\n133 519 Line 6.66667 12 7.33333 12\n133 823 Line 6.66667 11.3333 7.33333 11.3333\n133 824 Line 7.33333 11.3333 8 11.3333\n133 975 Line 8 11.3333 8 12\n134 221 Line 13.3333 17.3333 14 17.3333\n134 226 Line 11.3333 16.6667 12.6667 16.6667\n134 267 Line 12.6667 16.6667 14 16.6667\n134 282 Line 10 16.6667 11.3333 16.6667\n134 294 Line 14 16.6667 14 17.3333\n134 323 Line 9.33333 16.6667 9.33333 17.3333\n134 797 Line 9.33333 16.6667 10 16.6667\n135 229 Line 30.6667 12 30.6667 13.3333\n135 632 Line 30 12 30.6667 12\n135 717 Line 30 12.6667 30 13.3333\n135 959 Line 30 12 30 12.6667\n136 147 Line 28 12 28 12.6667\n136 220 Line 28 11.3333 28 12\n136 262 Line 26.6667 11.3333 27.3333 11.3333\n136 890 Line 26.6667 12 26.6667 12.6667\n136 931 Line 26.6667 11.3333 26.6667 12\n136 964 Line 27.3333 11.3333 28 11.3333\n136 967 Line 26.6667 12.6667 27.3333 12.6667\n136 968 Line 27.3333 12.6667 28 12.6667\n137 363 Line 27.3333 8 28 8\n137 476 Line 27.3333 9.33333 27.3333 10\n137 615 Line 28 8.66667 28 9.33333\n137 644 Line 28 9.33333 28 10\n137 691 Line 27.3333 8 27.3333 8.66667\n137 692 Line 27.3333 8.66667 27.3333 9.33333\n137 845 Line 28 8 28 8.66667\n137 963 Line 27.3333 10 28 10\n138 261 Line 1.33333 1.33333 1.33333 2\n138 274 Line 1.33333 1.33333 2.66667 1.33333\n138 281 Line 2 2.66667 2.66667 2.66667\n138 599 Line 1.33333 2 1.33333 2.66667\n138 636 Line 1.33333 2.66667 2 2.66667\n139 -1 Line 34 16 34 17.3333\n139 186 Line 33.3333 16 33.3333 17.3333\n139 912 Line 33.3333 16 34 16\n140 184 Line 27.3333 22 28.6667 22\n140 256 Line 27.3333 21.3333 27.3333 22\n140 257 Line 27.3333 21.3333 28 21.3333\n140 304 Line 28.6667 21.3333 28.6667 22\n141 207 Line 29.3333 16 29.3333 16.6667\n142 262 Line 26.6667 10 26.6667 10.6667\n142 379 Line 24.6667 9.33333 25.3333 9.33333\n142 380 Line 25.3333 9.33333 26 9.33333\n142 395 Line 24.6667 9.33333 24.6667 10\n142 471 Line 24.6667 10 24.6667 10.6667\n142 476 Line 26.6667 9.33333 26.6667 10\n142 499 Line 24.6667 10.6667 25.3333 10.6667\n142 594 Line 26 9.33333 26.6667 9.33333\n142 930 Line 26 10.6667 26.6667 10.6667\n142 932 Line 25.3333 10.6667 26 10.6667\n143 146 Line 20.6667 8 21.3333 8\n143 175 Line 20 8 20 8.66667\n143 227 Line 20 8 20.6667 8\n143 973 Line 20 8.66667 20.6667 8.66667\n143 974 Line 20.6667 8.66667 21.3333 8.66667\n144 899 Line 9.33333 13.3333 9.33333 14\n144 900 Line 9.33333 14 9.33333 14.6667\n144 955 Line 10 13.3333 10 14\n144 956 Line 10 14 10 14.6667\n145 -1 Line 1.33333 22.6667 2.66667 22.6667\n145 159 Line 1.33333 22 2 22\n145 216 Line 2 22 2.66667 22\n145 219 Line 2.66667 22 2.66667 22.6667\n146 227 Line 20.6667 7.33333 20.6667 8\n146 301 Line 20.6667 7.33333 22 7.33333\n146 812 Line 22.6667 7.33333 22.6667 8\n146 934 Line 22 7.33333 22.6667 7.33333\n147 160 Line 28 12.6667 29.3333 12.6667\n147 220 Line 28 12 28.6667 12\n147 825 Line 28.6667 12 29.3333 12\n147 959 Line 29.3333 12 29.3333 12.6667\n148 318 Line 8.66667 12 8.66667 12.6667\n148 321 Line 8.66667 12.6667 9.33333 12.6667\n148 498 Line 9.33333 12 9.33333 12.6667\n148 960 Line 8.66667 11.3333 9.33333 11.3333\n148 975 Line 8.66667 11.3333 8.66667 12\n149 189 Line 20 6 20 6.66667\n149 227 Line 20 6.66667 20 7.33333\n149 300 Line 19.3333 6 19.3333 7.33333\n149 768 Line 19.3333 7.33333 20 7.33333\n149 969 Line 19.3333 6 20 6\n150 265 Line 22 12.6667 22.6667 12.6667\n150 491 Line 22.6667 13.3333 23.3333 13.3333\n150 579 Line 23.3333 12.6667 23.3333 13.3333\n150 638 Line 22.6667 12.6667 23.3333 12.6667\n150 773 Line 22 12.6667 22 13.3333\n151 -1 Line 19.3333 0 20 0\n151 202 Line 20 0 20 1.33333\n152 187 Line 3.33333 3.33333 3.33333 4\n152 390 Line 3.33333 4 4 4\n152 551 Line 4 3.33333 4 4\n152 686 Line 3.33333 2.66667 4 2.66667\n152 730 Line 4 2.66667 4 3.33333\n153 165 Line 5.33333 0.666667 8 0.666667\n153 303 Line 8 0.666667 8 1.33333\n153 761 Line 6 1.33333 6.66667 1.33333\n154 179 Line 2.66667 18 4 18\n154 231 Line 2.66667 18 2.66667 18.6667\n155 -1 Line 4 22.6667 5.33333 22.6667\n155 194 Line 5.33333 22 5.33333 22.6667\n155 219 Line 4 22 4 22.6667\n156 218 Line 22 16 22 16.6667\n156 512 Line 22.6667 16 22.6667 16.6667\n156 514 Line 22 18 22.6667 18\n156 656 Line 22.6667 16.6667 22.6667 17.3333\n156 657 Line 22.6667 17.3333 22.6667 18\n157 -1 Line 0 14.6667 0 16\n157 204 Line 0.666667 14.6667 0.666667 15.3333\n157 319 Line 0 16 0.666667 16\n157 475 Line 0 14.6667 0.666667 14.6667\n158 236 Line 2.66667 10.6667 2.66667 12\n158 325 Line 3.33333 10.6667 3.33333 11.3333\n158 393 Line 2.66667 10.6667 3.33333 10.6667\n158 805 Line 3.33333 11.3333 3.33333 12\n158 952 Line 2.66667 12 3.33333 12\n159 173 Line 1.33333 21.3333 1.33333 22\n159 216 Line 2 20.6667 2 22\n160 717 Line 29.3333 12.6667 29.3333 13.3333\n160 968 Line 28 12.6667 28 13.3333\n161 -1 Line 34 2.66667 34 3.33333\n161 315 Line 30 3.33333 31.3333 3.33333\n161 843 Line 29.3333 3.33333 30 3.33333\n161 916 Line 29.3333 2.66667 29.3333 3.33333\n162 198 Line 17.3333 2 17.3333 3.33333\n162 254 Line 18.6667 1.33333 18.6667 4\n162 722 Line 17.3333 3.33333 17.3333 4\n162 808 Line 17.3333 4 18 4\n162 809 Line 18 4 18.6667 4\n162 957 Line 17.3333 1.33333 17.3333 2\n163 260 Line 32 6.66667 32.6667 6.66667\n163 642 Line 32.6667 6.66667 32.6667 7.33333\n163 888 Line 32 8.66667 32.6667 8.66667\n163 971 Line 32.6667 7.33333 32.6667 8\n163 972 Line 32.6667 8 32.6667 8.66667\n164 180 Line 5.33333 21.3333 6.66667 21.3333\n164 194 Line 5.33333 22 7.33333 22\n164 233 Line 7.33333 21.3333 7.33333 22\n165 -1 Line 5.33333 0 10 0\n165 303 Line 8 0.666667 10 0.666667\n166 193 Line 22 22 24 22\n166 271 Line 22 21.3333 24 21.3333\n166 995 Line 24 21.3333 24 22\n166 996 Line 22 21.3333 22 22\n167 -1 Line 26 0 26.6667 0\n167 705 Line 26 0 26 0.666667\n167 706 Line 26 0.666667 26 1.33333\n167 814 Line 26.6667 0.666667 26.6667 1.33333\n167 961 Line 26 1.33333 26.6667 1.33333\n168 210 Line 8.66667 15.3333 8.66667 16\n168 309 Line 8.66667 14.6667 8.66667 15.3333\n168 327 Line 8.66667 16 9.33333 16\n168 340 Line 9.33333 15.3333 9.33333 16\n168 900 Line 8.66667 14.6667 9.33333 14.6667\n169 267 Line 13.3333 15.3333 14.6667 15.3333\n169 450 Line 13.3333 14.6667 13.3333 15.3333\n169 484 Line 13.3333 14.6667 14 14.6667\n169 749 Line 14 14.6667 14.6667 14.6667\n169 942 Line 14.6667 14.6667 14.6667 15.3333\n170 260 Line 32.6667 5.33333 32.6667 6.66667\n170 642 Line 32.6667 6.66667 33.3333 6.66667\n170 840 Line 32.6667 5.33333 33.3333 5.33333\n171 228 Line 30.6667 20.6667 30.6667 21.3333\n171 247 Line 29.3333 20.6667 30 20.6667\n171 276 Line 30 20.6667 30.6667 20.6667\n172 480 Line 17.3333 8 17.3333 8.66667\n172 481 Line 17.3333 8.66667 17.3333 9.33333\n172 532 Line 17.3333 8 18 8\n172 998 Line 17.3333 9.33333 18 9.33333\n173 -1 Line 0 21.3333 0 22\n174 259 Line 0.666667 12 0.666667 12.6667\n174 293 Line 0.666667 12 1.33333 12\n174 310 Line 2 12 2 12.6667\n174 776 Line 0.666667 12.6667 1.33333 12.6667\n174 777 Line 1.33333 12.6667 2 12.6667\n174 813 Line 1.33333 12 2 12\n175 768 Line 19.3333 8 20 8\n175 810 Line 19.3333 8 19.3333 8.66667\n175 973 Line 20 8.66667 20 9.33333\n175 982 Line 19.3333 9.33333 20 9.33333\n176 585 Line 5.33333 17.3333 6 17.3333\n176 586 Line 6 17.3333 6.66667 17.3333\n176 658 Line 6.66667 16.6667 6.66667 17.3333\n176 990 Line 5.33333 16.6667 5.33333 17.3333\n177 312 Line 28.6667 0.666667 28.6667 2\n177 815 Line 28 0.666667 28 1.33333\n178 203 Line 26 16 26 17.3333\n178 225 Line 26 17.3333 26.6667 17.3333\n178 264 Line 26.6667 16 26.6667 17.3333\n178 313 Line 26 16 26.6667 16\n179 230 Line 4 17.3333 4 18\n179 511 Line 2.66667 17.3333 3.33333 17.3333\n179 690 Line 2.66667 17.3333 2.66667 18\n179 867 Line 3.33333 17.3333 4 17.3333\n181 -1 Line 15.3333 0 16 0\n181 223 Line 15.3333 0 15.3333 0.666667\n181 240 Line 16 0 16 1.33333\n181 709 Line 15.3333 1.33333 16 1.33333\n181 736 Line 15.3333 0.666667 15.3333 1.33333\n182 -1 Line 0 5.33333 0 6.66667\n182 245 Line 0.666667 6.66667 2 6.66667\n182 600 Line 1.33333 5.33333 2 5.33333\n182 719 Line 0 6.66667 0.666667 6.66667\n182 902 Line 2 5.33333 2 6\n182 903 Line 2 6 2 6.66667\n182 980 Line 0.666667 5.33333 1.33333 5.33333\n183 -1 Line 34 8.66667 34 10.6667\n183 392 Line 33.3333 10.6667 34 10.6667\n183 414 Line 33.3333 8.66667 33.3333 9.33333\n183 769 Line 33.3333 9.33333 33.3333 10\n183 770 Line 33.3333 10 33.3333 10.6667\n184 -1 Line 26.6667 22.6667 28.6667 22.6667\n184 256 Line 26.6667 22 27.3333 22\n184 304 Line 28.6667 22 28.6667 22.6667\n184 565 Line 26.6667 22 26.6667 22.6667\n185 741 Line 10 10.6667 10.6667 10.6667\n185 774 Line 10 12 10.6667 12\n185 999 Line 10.6667 11.3333 10.6667 12\n186 288 Line 32.6667 16 32.6667 17.3333\n186 892 Line 32.6667 16 33.3333 16\n187 243 Line 2.66667 4 2.66667 4.66667\n187 281 Line 2.66667 3.33333 2.66667 4\n187 390 Line 3.33333 4 3.33333 4.66667\n187 634 Line 2.66667 4.66667 3.33333 4.66667\n188 -1 Line 22.6667 0 24.6667 0\n188 307 Line 24 2.66667 24.6667 2.66667\n188 314 Line 22.6667 0 22.6667 1.33333\n188 643 Line 24.6667 0 24.6667 0.666667\n188 943 Line 24.6667 0.666667 24.6667 1.33333\n189 227 Line 20 6.66667 20.6667 6.66667\n189 301 Line 20.6667 6.66667 22 6.66667\n189 789 Line 22 6 22 6.66667\n189 871 Line 20.6667 6 21.3333 6\n189 880 Line 21.3333 6 22 6\n189 970 Line 20 6 20.6667 6\n190 196 Line 18 15.3333 18.6667 15.3333\n190 263 Line 17.3333 15.3333 18 15.3333\n190 385 Line 17.3333 14.6667 17.3333 15.3333\n190 465 Line 17.3333 14.6667 18 14.6667\n190 466 Line 18 14.6667 18.6667 14.6667\n190 901 Line 18.6667 14.6667 18.6667 15.3333\n191 -1 Line 34 18 34 19.3333\n191 250 Line 33.3333 19.3333 34 19.3333\n192 234 Line 10.6667 21.3333 10.6667 22\n192 422 Line 12.6667 21.3333 12.6667 22\n193 -1 Line 21.3333 22.6667 24.6667 22.6667\n193 796 Line 21.3333 22 21.3333 22.6667\n193 834 Line 24.6667 22 24.6667 22.6667\n193 995 Line 24 22 24.6667 22\n193 996 Line 21.3333 22 22 22\n194 -1 Line 5.33333 22.6667 7.33333 22.6667\n195 286 Line 4.66667 15.3333 4.66667 16\n195 316 Line 3.33333 16 4.66667 16\n195 467 Line 3.33333 15.3333 3.33333 16\n196 253 Line 18 16 19.3333 16\n196 263 Line 18 15.3333 18 16\n196 901 Line 18.6667 15.3333 19.3333 15.3333\n196 919 Line 19.3333 15.3333 19.3333 16\n197 218 Line 20.6667 16 21.3333 16\n197 628 Line 20.6667 14.6667 21.3333 14.6667\n197 695 Line 21.3333 14.6667 21.3333 15.3333\n197 696 Line 21.3333 15.3333 21.3333 16\n197 944 Line 20.6667 14.6667 20.6667 15.3333\n197 945 Line 20.6667 15.3333 20.6667 16\n198 251 Line 16.6667 2 16.6667 2.66667\n198 611 Line 16.6667 2.66667 16.6667 3.33333\n198 722 Line 16.6667 3.33333 17.3333 3.33333\n198 957 Line 16.6667 2 17.3333 2\n199 223 Line 14 0.666667 14.6667 0.666667\n199 342 Line 13.3333 0.666667 13.3333 1.33333\n199 434 Line 13.3333 1.33333 14 1.33333\n199 452 Line 13.3333 0.666667 14 0.666667\n199 736 Line 14.6667 0.666667 14.6667 1.33333\n199 771 Line 14 1.33333 14.6667 1.33333\n200 367 Line 9.33333 6.66667 9.33333 7.33333\n200 517 Line 9.33333 6.66667 10 6.66667\n200 707 Line 10 6.66667 10.6667 6.66667\n200 887 Line 10.6667 6.66667 10.6667 7.33333\n200 926 Line 9.33333 7.33333 10 7.33333\n200 927 Line 10 7.33333 10.6667 7.33333\n201 205 Line 32.6667 13.3333 33.3333 13.3333\n201 660 Line 32.6667 12 33.3333 12\n201 923 Line 33.3333 12 33.3333 12.6667\n201 924 Line 33.3333 12.6667 33.3333 13.3333\n202 -1 Line 20 0 20.6667 0\n202 837 Line 20 4 20.6667 4\n202 941 Line 20.6667 3.33333 20.6667 4\n202 948 Line 20 3.33333 20 4\n203 225 Line 24.6667 17.3333 26 17.3333\n203 273 Line 25.3333 16 26 16\n203 430 Line 24.6667 16 24.6667 16.6667\n203 864 Line 24.6667 16 25.3333 16\n203 922 Line 24.6667 16.6667 24.6667 17.3333\n204 737 Line 2.66667 14.6667 2.66667 15.3333\n205 419 Line 33.3333 14 33.3333 14.6667\n205 487 Line 33.3333 13.3333 33.3333 14\n205 891 Line 32.6667 14.6667 33.3333 14.6667\n206 236 Line 2 10.6667 2.66667 10.6667\n206 393 Line 2.66667 10 2.66667 10.6667\n206 425 Line 2.66667 9.33333 2.66667 10\n206 597 Line 2 8.66667 2.66667 8.66667\n206 699 Line 2.66667 8.66667 2.66667 9.33333\n207 242 Line 28 17.3333 29.3333 17.3333\n207 270 Line 28 16 28 17.3333\n208 266 Line 27.3333 13.3333 27.3333 14.6667\n208 763 Line 26.6667 14 26.6667 14.6667\n208 967 Line 26.6667 13.3333 27.3333 13.3333\n209 306 Line 23.3333 7.33333 24.6667 7.33333\n209 732 Line 24.6667 6.66667 24.6667 7.33333\n209 812 Line 22.6667 7.33333 23.3333 7.33333\n209 934 Line 22.6667 6.66667 22.6667 7.33333\n210 285 Line 7.33333 16 8.66667 16\n210 309 Line 7.33333 15.3333 8.66667 15.3333\n211 224 Line 32 19.3333 32 22\n211 250 Line 33.3333 19.3333 33.3333 20.6667\n211 827 Line 32 22 32.6667 22\n211 828 Line 32.6667 22 33.3333 22\n211 881 Line 33.3333 20.6667 33.3333 21.3333\n211 882 Line 33.3333 21.3333 33.3333 22\n212 225 Line 24.6667 18.6667 24.6667 20\n212 317 Line 24 18.6667 24.6667 18.6667\n212 869 Line 24 20 24.6667 20\n213 279 Line 8.66667 2 10 2\n213 482 Line 9.33333 2.66667 10 2.66667\n213 523 Line 10 2 10 2.66667\n213 788 Line 8.66667 2.66667 9.33333 2.66667\n214 297 Line 31.3333 10.6667 32.6667 10.6667\n214 652 Line 31.3333 10 32 10\n214 653 Line 32 10 32.6667 10\n214 770 Line 32.6667 10 32.6667 10.6667\n214 920 Line 31.3333 10 31.3333 10.6667\n215 234 Line 8.66667 21.3333 10 21.3333\n216 981 Line 2 20.6667 2.66667 20.6667\n217 308 Line 21.3333 4.66667 21.3333 5.33333\n217 880 Line 21.3333 5.33333 22 5.33333\n217 954 Line 21.3333 4.66667 22 4.66667\n217 958 Line 22 5.33333 22.6667 5.33333\n217 984 Line 22.6667 4.66667 22.6667 5.33333\n218 696 Line 21.3333 16 22 16\n218 697 Line 20.6667 16 20.6667 16.6667\n219 -1 Line 2.66667 22.6667 4 22.6667\n220 825 Line 28.6667 11.3333 28.6667 12\n220 904 Line 28 10.6667 28.6667 10.6667\n220 964 Line 28 10.6667 28 11.3333\n221 294 Line 14 17.3333 14 18\n221 343 Line 14 18.6667 14 19.3333\n221 537 Line 13.3333 19.3333 14 19.3333\n221 540 Line 14 18 14 18.6667\n222 309 Line 7.33333 14.6667 8.66667 14.6667\n222 378 Line 8 13.3333 8.66667 13.3333\n222 729 Line 7.33333 13.3333 8 13.3333\n222 899 Line 8.66667 13.3333 8.66667 14\n222 900 Line 8.66667 14 8.66667 14.6667\n223 -1 Line 14 0 15.3333 0\n223 452 Line 14 0 14 0.666667\n223 736 Line 14.6667 0.666667 15.3333 0.666667\n224 228 Line 31.3333 19.3333 31.3333 21.3333\n224 311 Line 31.3333 21.3333 31.3333 22\n224 829 Line 31.3333 22 32 22\n225 242 Line 28 17.3333 28 19.3333\n225 257 Line 27.3333 20 28 20\n225 264 Line 26.6667 17.3333 27.3333 17.3333\n225 270 Line 27.3333 17.3333 28 17.3333\n225 299 Line 24.6667 20 26 20\n225 317 Line 24.6667 17.3333 24.6667 18.6667\n226 267 Line 12.6667 16 12.6667 16.6667\n226 282 Line 11.3333 16 11.3333 16.6667\n226 365 Line 11.3333 16 12 16\n226 366 Line 12 16 12.6667 16\n227 301 Line 20.6667 6.66667 20.6667 7.33333\n227 768 Line 20 7.33333 20 8\n228 276 Line 30.6667 19.3333 30.6667 20.6667\n228 311 Line 30.6667 21.3333 31.3333 21.3333\n229 275 Line 31.3333 12 32 12\n229 633 Line 30.6667 12 31.3333 12\n230 585 Line 5.33333 17.3333 5.33333 18\n230 868 Line 4 17.3333 4.66667 17.3333\n230 990 Line 4.66667 17.3333 5.33333 17.3333\n231 690 Line 2 18 2.66667 18\n231 981 Line 2 20 2.66667 20\n232 472 Line 14.6667 5.33333 15.3333 5.33333\n232 494 Line 14.6667 4 15.3333 4\n232 785 Line 14.6667 4 14.6667 4.66667\n232 786 Line 14.6667 4.66667 14.6667 5.33333\n233 234 Line 8.66667 21.3333 8.66667 22\n235 417 Line 12 4.66667 12.6667 4.66667\n235 510 Line 11.3333 4 11.3333 4.66667\n235 582 Line 12.6667 4 12.6667 4.66667\n235 965 Line 11.3333 4 12 4\n235 966 Line 12 4 12.6667 4\n235 989 Line 11.3333 4.66667 12 4.66667\n236 310 Line 2 12 2.66667 12\n236 813 Line 2 11.3333 2 12\n237 479 Line 5.33333 12 5.33333 12.6667\n237 701 Line 4 12.6667 4.66667 12.6667\n237 806 Line 4 12 4 12.6667\n238 253 Line 18 16 18 16.6667\n238 263 Line 16.6667 16 18 16\n238 296 Line 16.6667 16.6667 17.3333 16.6667\n238 925 Line 16.6667 16 16.6667 16.6667\n239 269 Line 4.66667 6.66667 6 6.66667\n239 278 Line 5.33333 6 6 6\n239 550 Line 4 6 4 6.66667\n239 851 Line 4 6.66667 4.66667 6.66667\n239 985 Line 6 6 6 6.66667\n240 -1 Line 16 0 16.6667 0\n240 710 Line 16 1.33333 16.6667 1.33333\n240 723 Line 16.6667 0 16.6667 0.666667\n240 724 Line 16.6667 0.666667 16.6667 1.33333\n241 244 Line 1.33333 16.6667 2 16.6667\n241 383 Line 2.66667 16 2.66667 16.6667\n241 421 Line 2 16.6667 2.66667 16.6667\n241 711 Line 1.33333 16 1.33333 16.6667\n243 281 Line 2 4 2.66667 4\n243 291 Line 2 4 2 4.66667\n243 600 Line 2 4.66667 2 5.33333\n243 634 Line 2.66667 4.66667 2.66667 5.33333\n243 902 Line 2 5.33333 2.66667 5.33333\n244 -1 Line 0 16.6667 0 17.3333\n244 319 Line 0 16.6667 0.666667 16.6667\n244 421 Line 2 16.6667 2 17.3333\n244 711 Line 0.666667 16.6667 1.33333 16.6667\n245 719 Line 0.666667 6.66667 0.666667 7.33333\n245 807 Line 2 6.66667 2 7.33333\n246 249 Line 21.3333 2.66667 22 2.66667\n246 941 Line 21.3333 3.33333 21.3333 4\n246 954 Line 21.3333 4 22 4\n247 276 Line 30 19.3333 30 20.6667\n248 287 Line 14 21.3333 15.3333 21.3333\n248 331 Line 14 20 14 20.6667\n248 443 Line 14 20.6667 14 21.3333\n248 629 Line 14 20 14.6667 20\n248 630 Line 14.6667 20 15.3333 20\n249 -1 Line 21.3333 0 22 0\n249 314 Line 22 0 22 1.33333\n250 -1 Line 34 19.3333 34 20.6667\n250 881 Line 33.3333 20.6667 34 20.6667\n251 539 Line 15.3333 2 15.3333 2.66667\n251 610 Line 15.3333 2.66667 16 2.66667\n251 611 Line 16 2.66667 16.6667 2.66667\n251 709 Line 15.3333 2 16 2\n251 710 Line 16 2 16.6667 2\n252 268 Line 3.33333 1.33333 4 1.33333\n252 686 Line 3.33333 2 4 2\n252 687 Line 4 2 4.66667 2\n252 994 Line 4 1.33333 4.66667 1.33333\n253 641 Line 19.3333 16 19.3333 16.6667\n253 929 Line 18.6667 16.6667 19.3333 16.6667\n254 948 Line 19.3333 3.33333 19.3333 4\n255 295 Line 30.6667 8.66667 31.3333 8.66667\n255 917 Line 29.3333 8.66667 29.3333 9.33333\n256 565 Line 26 22 26.6667 22\n256 833 Line 26 21.3333 26 22\n258 280 Line 18.6667 19.3333 19.3333 19.3333\n258 929 Line 18.6667 17.3333 19.3333 17.3333\n259 -1 Line 0 12 0 13.3333\n259 776 Line 0.666667 12.6667 0.666667 13.3333\n260 302 Line 32 5.33333 32.6667 5.33333\n261 -1 Line 0 0.666667 0 2\n261 274 Line 1.33333 0.666667 1.33333 1.33333\n261 598 Line 0 2 0.666667 2\n261 599 Line 0.666667 2 1.33333 2\n262 476 Line 26.6667 10 27.3333 10\n262 930 Line 26.6667 10.6667 26.6667 11.3333\n262 963 Line 27.3333 10 27.3333 10.6667\n262 964 Line 27.3333 10.6667 27.3333 11.3333\n263 385 Line 16.6667 15.3333 17.3333 15.3333\n263 399 Line 16.6667 15.3333 16.6667 16\n264 270 Line 27.3333 16 27.3333 17.3333\n265 330 Line 22 12 22.6667 12\n265 410 Line 21.3333 12 22 12\n265 572 Line 21.3333 12 21.3333 12.6667\n265 638 Line 22.6667 12 22.6667 12.6667\n265 773 Line 21.3333 12.6667 22 12.6667\n266 968 Line 27.3333 13.3333 28 13.3333\n267 294 Line 14 16.6667 14.6667 16.6667\n267 338 Line 15.3333 16 15.3333 16.6667\n267 355 Line 14.6667 16.6667 15.3333 16.6667\n267 366 Line 12.6667 15.3333 12.6667 16\n267 450 Line 12.6667 15.3333 13.3333 15.3333\n267 910 Line 15.3333 15.3333 15.3333 16\n267 942 Line 14.6667 15.3333 15.3333 15.3333\n268 -1 Line 3.33333 0 4 0\n268 624 Line 3.33333 0 3.33333 0.666667\n268 993 Line 4 0 4 0.666667\n268 994 Line 4 0.666667 4 1.33333\n269 851 Line 4.66667 6.66667 4.66667 7.33333\n271 299 Line 24.6667 20.6667 24.6667 21.3333\n271 869 Line 24 20.6667 24.6667 20.6667\n271 873 Line 22 20.6667 22.6667 20.6667\n271 995 Line 24 21.3333 24.6667 21.3333\n272 472 Line 14.6667 6 15.3333 6\n272 541 Line 14.6667 6 14.6667 6.66667\n272 607 Line 15.3333 6 15.3333 6.66667\n272 874 Line 15.3333 6.66667 15.3333 7.33333\n273 313 Line 26 14.6667 26 16\n273 765 Line 25.3333 14.6667 26 14.6667\n273 864 Line 25.3333 15.3333 25.3333 16\n273 866 Line 25.3333 14.6667 25.3333 15.3333\n275 297 Line 31.3333 11.3333 32.6667 11.3333\n275 633 Line 31.3333 11.3333 31.3333 12\n275 660 Line 32.6667 11.3333 32.6667 12\n277 361 Line 26 6 26 6.66667\n277 732 Line 24.6667 6.66667 25.3333 6.66667\n277 733 Line 25.3333 6.66667 26 6.66667\n278 373 Line 6.66667 5.33333 6.66667 6\n278 782 Line 5.33333 5.33333 6 5.33333\n278 783 Line 6 5.33333 6.66667 5.33333\n278 985 Line 6 6 6.66667 6\n279 303 Line 8.66667 1.33333 10 1.33333\n279 523 Line 10 2 10.6667 2\n279 742 Line 10.6667 1.33333 10.6667 2\n280 950 Line 18.6667 20.6667 19.3333 20.6667\n281 291 Line 2 3.33333 2 4\n281 636 Line 2 2.66667 2 3.33333\n282 544 Line 10 16 10.6667 16\n282 545 Line 10.6667 16 11.3333 16\n282 797 Line 10 16 10 16.6667\n283 463 Line 17.3333 11.3333 17.3333 12\n283 702 Line 16 11.3333 16.6667 11.3333\n283 703 Line 16.6667 11.3333 17.3333 11.3333\n283 913 Line 16 12 16.6667 12\n283 914 Line 16.6667 12 17.3333 12\n284 553 Line 13.3333 11.3333 14 11.3333\n284 556 Line 14 10 14 10.6667\n284 557 Line 14 10.6667 14 11.3333\n284 762 Line 13.3333 10 14 10\n284 947 Line 13.3333 10 13.3333 10.6667\n285 327 Line 8.66667 16 8.66667 16.6667\n285 647 Line 7.33333 16.6667 8 16.6667\n285 648 Line 8 16.6667 8.66667 16.6667\n285 792 Line 7.33333 16 7.33333 16.6667\n286 529 Line 4.66667 16 5.33333 16\n287 -1 Line 14 22.6667 15.3333 22.6667\n288 870 Line 32 16 32.6667 16\n289 463 Line 17.3333 11.3333 18 11.3333\n289 640 Line 17.3333 10 17.3333 10.6667\n289 703 Line 17.3333 10.6667 17.3333 11.3333\n289 998 Line 17.3333 10 18 10\n290 -1 Line 16.6667 22.6667 17.3333 22.6667\n291 600 Line 1.33333 4.66667 2 4.66667\n291 636 Line 1.33333 3.33333 2 3.33333\n291 978 Line 1.33333 3.33333 1.33333 4\n291 979 Line 1.33333 4 1.33333 4.66667\n292 614 Line 2.66667 13.3333 2.66667 14\n292 737 Line 2.66667 14.6667 3.33333 14.6667\n292 953 Line 2.66667 13.3333 3.33333 13.3333\n293 813 Line 1.33333 11.3333 1.33333 12\n293 992 Line 0.666667 10.6667 1.33333 10.6667\n294 355 Line 14.6667 16.6667 14.6667 17.3333\n294 356 Line 14.6667 17.3333 14.6667 18\n294 540 Line 14 18 14.6667 18\n295 623 Line 30.6667 7.33333 30.6667 8\n296 505 Line 16 16.6667 16 17.3333\n296 925 Line 16 16.6667 16.6667 16.6667\n297 659 Line 32.6667 10.6667 32.6667 11.3333\n297 921 Line 31.3333 10.6667 31.3333 11.3333\n298 507 Line 28 4 28 4.66667\n298 508 Line 28 4.66667 28 5.33333\n298 564 Line 28 5.33333 28.6667 5.33333\n298 818 Line 28 4 28.6667 4\n299 832 Line 24.6667 21.3333 25.3333 21.3333\n299 833 Line 25.3333 21.3333 26 21.3333\n299 869 Line 24.6667 20 24.6667 20.6667\n300 768 Line 19.3333 7.33333 19.3333 8\n300 810 Line 18.6667 8 19.3333 8\n300 896 Line 18.6667 7.33333 18.6667 8\n300 897 Line 18.6667 6 18.6667 6.66667\n300 898 Line 18.6667 6.66667 18.6667 7.33333\n301 934 Line 22 6.66667 22 7.33333\n302 604 Line 31.3333 4.66667 31.3333 5.33333\n302 840 Line 32.6667 4.66667 32.6667 5.33333\n302 854 Line 31.3333 4.66667 32 4.66667\n302 855 Line 32 4.66667 32.6667 4.66667\n304 -1 Line 28.6667 22.6667 29.3333 22.6667\n305 856 Line 23.3333 5.33333 24 5.33333\n305 958 Line 22.6667 5.33333 22.6667 6\n305 984 Line 22.6667 5.33333 23.3333 5.33333\n306 336 Line 24 8 24.6667 8\n306 350 Line 24.6667 7.33333 24.6667 8\n306 682 Line 23.3333 8 24 8\n306 812 Line 23.3333 7.33333 23.3333 8\n307 760 Line 24.6667 2.66667 24.6667 3.33333\n307 799 Line 24.6667 3.33333 24.6667 4\n307 858 Line 24 4 24.6667 4\n308 837 Line 20.6667 4 20.6667 4.66667\n308 838 Line 20.6667 4.66667 20.6667 5.33333\n308 871 Line 20.6667 5.33333 21.3333 5.33333\n308 941 Line 20.6667 4 21.3333 4\n308 954 Line 21.3333 4 21.3333 4.66667\n310 614 Line 2 13.3333 2.66667 13.3333\n310 777 Line 2 12.6667 2 13.3333\n310 952 Line 2.66667 12 2.66667 12.6667\n310 953 Line 2.66667 12.6667 2.66667 13.3333\n311 -1 Line 30.6667 22.6667 31.3333 22.6667\n311 829 Line 31.3333 22 31.3333 22.6667\n312 631 Line 28.6667 0.666667 29.3333 0.666667\n312 915 Line 28.6667 2 29.3333 2\n313 763 Line 26 14.6667 26.6667 14.6667\n314 -1 Line 22 0 22.6667 0\n315 603 Line 30.6667 4 31.3333 4\n315 843 Line 30 3.33333 30 4\n315 883 Line 30 4 30.6667 4\n316 383 Line 3.33333 16 3.33333 16.6667\n316 529 Line 4.66667 16 4.66667 16.6667\n316 867 Line 3.33333 16.6667 4 16.6667\n316 868 Line 4 16.6667 4.66667 16.6667\n317 478 Line 24 18 24 18.6667\n317 513 Line 24 17.3333 24 18\n317 922 Line 24 17.3333 24.6667 17.3333\n318 353 Line 8 12 8 12.6667\n318 378 Line 8 12.6667 8.66667 12.6667\n318 975 Line 8 12 8.66667 12\n319 -1 Line 0 16 0 16.6667\n319 711 Line 0.666667 16 0.666667 16.6667\n320 344 Line 14.6667 18.6667 15.3333 18.6667\n320 356 Line 14.6667 18 15.3333 18\n320 540 Line 14.6667 18 14.6667 18.6667\n321 378 Line 8.66667 12.6667 8.66667 13.3333\n321 899 Line 8.66667 13.3333 9.33333 13.3333\n322 453 Line 20 12 20 12.6667\n322 572 Line 20.6667 12 20.6667 12.6667\n322 669 Line 20 12.6667 20.6667 12.6667\n323 327 Line 8.66667 16.6667 9.33333 16.6667\n323 648 Line 8.66667 16.6667 8.66667 17.3333\n324 400 Line 12.6667 7.33333 12.6667 8\n324 438 Line 13.3333 7.33333 13.3333 8\n324 781 Line 12.6667 8 13.3333 8\n325 548 Line 3.33333 10.6667 4 10.6667\n325 574 Line 4 10.6667 4 11.3333\n325 805 Line 3.33333 11.3333 4 11.3333\n326 411 Line 16 13.3333 16 14\n326 444 Line 15.3333 14 16 14\n326 561 Line 15.3333 13.3333 15.3333 14\n327 797 Line 9.33333 16 9.33333 16.6667\n328 451 Line 27.3333 5.33333 27.3333 6\n328 508 Line 27.3333 5.33333 28 5.33333\n328 564 Line 28 5.33333 28 6\n329 330 Line 22 11.3333 22.6667 11.3333\n329 409 Line 22 10.6667 22 11.3333\n329 474 Line 22 10.6667 22.6667 10.6667\n330 410 Line 22 11.3333 22 12\n331 443 Line 13.3333 20.6667 14 20.6667\n331 537 Line 13.3333 20 14 20\n332 397 Line 5.33333 3.33333 6 3.33333\n332 680 Line 6 2.66667 6 3.33333\n332 685 Line 5.33333 2.66667 6 2.66667\n332 731 Line 5.33333 2.66667 5.33333 3.33333\n333 439 Line 22.6667 10 23.3333 10\n333 470 Line 23.3333 10 23.3333 10.6667\n333 474 Line 22.6667 10 22.6667 10.6667\n334 391 Line 4.66667 4 4.66667 4.66667\n334 486 Line 4.66667 4.66667 5.33333 4.66667\n334 552 Line 4.66667 4 5.33333 4\n334 801 Line 5.33333 4 5.33333 4.66667\n335 358 Line 19.3333 11.3333 19.3333 12\n335 406 Line 18.6667 12 19.3333 12\n335 464 Line 18.6667 11.3333 18.6667 12\n335 794 Line 18.6667 11.3333 19.3333 11.3333\n336 337 Line 24 8.66667 24.6667 8.66667\n336 436 Line 24.6667 8 24.6667 8.66667\n336 682 Line 24 8 24 8.66667\n337 379 Line 24.6667 8.66667 24.6667 9.33333\n337 395 Line 24 9.33333 24.6667 9.33333\n337 683 Line 24 8.66667 24 9.33333\n338 505 Line 15.3333 16.6667 16 16.6667\n338 910 Line 15.3333 16 16 16\n338 925 Line 16 16 16 16.6667\n339 394 Line 10.6667 14.6667 11.3333 14.6667\n339 605 Line 11.3333 14 11.3333 14.6667\n339 956 Line 10.6667 14 10.6667 14.6667\n340 544 Line 10 15.3333 10 16\n340 797 Line 9.33333 16 10 16\n341 -1 Line 12.6667 0 13.3333 0\n341 342 Line 12.6667 0.666667 13.3333 0.666667\n341 452 Line 13.3333 0 13.3333 0.666667\n341 716 Line 12.6667 0 12.6667 0.666667\n342 403 Line 12.6667 0.666667 12.6667 1.33333\n342 433 Line 12.6667 1.33333 13.3333 1.33333\n343 344 Line 14.6667 18.6667 14.6667 19.3333\n343 540 Line 14 18.6667 14.6667 18.6667\n343 629 Line 14 19.3333 14.6667 19.3333\n344 630 Line 14.6667 19.3333 15.3333 19.3333\n345 346 Line 16.6667 14 16.6667 14.6667\n345 376 Line 16 14.6667 16.6667 14.6667\n345 411 Line 16 14 16.6667 14\n345 444 Line 16 14 16 14.6667\n346 385 Line 16.6667 14.6667 17.3333 14.6667\n346 412 Line 16.6667 14 17.3333 14\n346 465 Line 17.3333 14 17.3333 14.6667\n347 348 Line 8.66667 6 9.33333 6\n347 407 Line 8.66667 5.33333 9.33333 5.33333\n347 424 Line 9.33333 5.33333 9.33333 6\n347 432 Line 8.66667 5.33333 8.66667 6\n348 367 Line 8.66667 6.66667 9.33333 6.66667\n348 515 Line 8.66667 6 8.66667 6.66667\n348 517 Line 9.33333 6 9.33333 6.66667\n349 416 Line 14 12 14 12.6667\n349 553 Line 13.3333 12 14 12\n349 562 Line 13.3333 12.6667 14 12.6667\n349 609 Line 13.3333 12 13.3333 12.6667\n350 351 Line 25.3333 7.33333 25.3333 8\n350 436 Line 24.6667 8 25.3333 8\n350 732 Line 24.6667 7.33333 25.3333 7.33333\n351 375 Line 26 7.33333 26 8\n351 437 Line 25.3333 8 26 8\n351 733 Line 25.3333 7.33333 26 7.33333\n352 384 Line 16.6667 7.33333 16.6667 8\n352 480 Line 16.6667 8 17.3333 8\n352 532 Line 17.3333 7.33333 17.3333 8\n352 746 Line 16.6667 7.33333 17.3333 7.33333\n353 519 Line 7.33333 12 7.33333 12.6667\n353 729 Line 7.33333 12.6667 8 12.6667\n354 502 Line 12 12.6667 12 13.3333\n354 559 Line 12.6667 12.6667 12.6667 13.3333\n354 608 Line 12 12.6667 12.6667 12.6667\n354 811 Line 12 13.3333 12.6667 13.3333\n355 356 Line 14.6667 17.3333 15.3333 17.3333\n355 505 Line 15.3333 16.6667 15.3333 17.3333\n357 358 Line 19.3333 11.3333 20 11.3333\n357 458 Line 20 10.6667 20 11.3333\n357 794 Line 19.3333 10.6667 19.3333 11.3333\n357 983 Line 19.3333 10.6667 20 10.6667\n358 453 Line 19.3333 12 20 12\n359 596 Line 2.66667 7.33333 2.66667 8\n359 635 Line 2.66667 7.33333 3.33333 7.33333\n359 698 Line 2.66667 8 3.33333 8\n359 734 Line 3.33333 7.33333 3.33333 8\n360 442 Line 14.6667 9.33333 15.3333 9.33333\n360 718 Line 14.6667 8.66667 14.6667 9.33333\n360 906 Line 15.3333 8.66667 15.3333 9.33333\n361 374 Line 26 6.66667 26.6667 6.66667\n361 428 Line 26.6667 6 26.6667 6.66667\n362 363 Line 27.3333 7.33333 27.3333 8\n362 375 Line 26.6667 7.33333 26.6667 8\n362 429 Line 26.6667 7.33333 27.3333 7.33333\n362 691 Line 26.6667 8 27.3333 8\n363 844 Line 28 7.33333 28 8\n364 404 Line 8 10 8.66667 10\n364 462 Line 8 10.6667 8.66667 10.6667\n364 531 Line 8 10 8 10.6667\n364 664 Line 8.66667 10 8.66667 10.6667\n365 366 Line 12 15.3333 12 16\n365 500 Line 11.3333 15.3333 12 15.3333\n365 545 Line 11.3333 15.3333 11.3333 16\n366 501 Line 12 15.3333 12.6667 15.3333\n367 528 Line 8.66667 6.66667 8.66667 7.33333\n367 651 Line 8.66667 7.33333 9.33333 7.33333\n368 482 Line 10 2.66667 10 3.33333\n368 489 Line 10.6667 2.66667 10.6667 3.33333\n368 523 Line 10 2.66667 10.6667 2.66667\n368 566 Line 10 3.33333 10.6667 3.33333\n369 527 Line 7.33333 6.66667 7.33333 7.33333\n369 533 Line 6.66667 6.66667 7.33333 6.66667\n369 665 Line 6.66667 7.33333 7.33333 7.33333\n370 390 Line 3.33333 4.66667 4 4.66667\n370 485 Line 4 4.66667 4 5.33333\n370 549 Line 3.33333 5.33333 4 5.33333\n370 634 Line 3.33333 4.66667 3.33333 5.33333\n371 447 Line 19.3333 13.3333 19.3333 14\n371 454 Line 19.3333 13.3333 20 13.3333\n371 670 Line 20 13.3333 20 14\n372 405 Line 18 12 18 12.6667\n372 463 Line 17.3333 12 18 12\n372 577 Line 17.3333 12.6667 18 12.6667\n372 914 Line 17.3333 12 17.3333 12.6667\n373 431 Line 7.33333 5.33333 7.33333 6\n373 533 Line 6.66667 6 7.33333 6\n373 563 Line 6.66667 5.33333 7.33333 5.33333\n374 375 Line 26 7.33333 26.6667 7.33333\n374 429 Line 26.6667 6.66667 26.6667 7.33333\n374 733 Line 26 6.66667 26 7.33333\n375 593 Line 26 8 26.6667 8\n376 385 Line 16.6667 14.6667 16.6667 15.3333\n376 399 Line 16 15.3333 16.6667 15.3333\n376 909 Line 16 14.6667 16 15.3333\n377 435 Line 5.33333 11.3333 6 11.3333\n377 490 Line 6 10.6667 6 11.3333\n377 575 Line 5.33333 10.6667 5.33333 11.3333\n377 758 Line 5.33333 10.6667 6 10.6667\n378 729 Line 8 12.6667 8 13.3333\n379 380 Line 25.3333 8.66667 25.3333 9.33333\n379 436 Line 24.6667 8.66667 25.3333 8.66667\n380 437 Line 25.3333 8.66667 26 8.66667\n380 594 Line 26 8.66667 26 9.33333\n381 382 Line 14.6667 10.6667 15.3333 10.6667\n381 442 Line 14.6667 10 15.3333 10\n381 556 Line 14.6667 10 14.6667 10.6667\n381 862 Line 15.3333 10 15.3333 10.6667\n382 426 Line 15.3333 10.6667 15.3333 11.3333\n382 557 Line 14.6667 10.6667 14.6667 11.3333\n382 738 Line 14.6667 11.3333 15.3333 11.3333\n383 467 Line 2.66667 16 3.33333 16\n383 511 Line 2.66667 16.6667 3.33333 16.6667\n384 846 Line 16 8 16.6667 8\n384 875 Line 16 7.33333 16 8\n386 387 Line 7.33333 9.33333 7.33333 10\n386 530 Line 6.66667 10 7.33333 10\n386 589 Line 6.66667 9.33333 7.33333 9.33333\n386 617 Line 6.66667 9.33333 6.66667 10\n387 404 Line 8 9.33333 8 10\n387 531 Line 7.33333 10 8 10\n387 590 Line 7.33333 9.33333 8 9.33333\n388 389 Line 16.6667 12.6667 16.6667 13.3333\n388 411 Line 16 13.3333 16.6667 13.3333\n388 913 Line 16 12.6667 16.6667 12.6667\n389 412 Line 16.6667 13.3333 17.3333 13.3333\n389 577 Line 17.3333 12.6667 17.3333 13.3333\n389 914 Line 16.6667 12.6667 17.3333 12.6667\n390 391 Line 4 4 4 4.66667\n391 485 Line 4 4.66667 4.66667 4.66667\n391 551 Line 4 4 4.66667 4\n392 -1 Line 34 10.6667 34 11.3333\n392 659 Line 33.3333 10.6667 33.3333 11.3333\n392 908 Line 33.3333 11.3333 34 11.3333\n393 425 Line 2.66667 10 3.33333 10\n393 548 Line 3.33333 10 3.33333 10.6667\n394 500 Line 11.3333 14.6667 11.3333 15.3333\n394 545 Line 10.6667 15.3333 11.3333 15.3333\n395 440 Line 24 9.33333 24 10\n395 471 Line 24 10 24.6667 10\n396 427 Line 13.3333 2.66667 13.3333 3.33333\n396 555 Line 12.6667 2.66667 12.6667 3.33333\n396 570 Line 12.6667 2.66667 13.3333 2.66667\n396 581 Line 12.6667 3.33333 13.3333 3.33333\n397 398 Line 6 3.33333 6 4\n397 552 Line 5.33333 3.33333 5.33333 4\n397 801 Line 5.33333 4 6 4\n398 680 Line 6 3.33333 6.66667 3.33333\n398 802 Line 6 4 6.66667 4\n398 830 Line 6.66667 3.33333 6.66667 4\n399 910 Line 16 15.3333 16 16\n399 925 Line 16 16 16.6667 16\n400 401 Line 12 7.33333 12.6667 7.33333\n400 755 Line 12 7.33333 12 8\n400 780 Line 12 8 12.6667 8\n401 525 Line 12 6.66667 12.6667 6.66667\n401 756 Line 12 6.66667 12 7.33333\n402 403 Line 12 0.666667 12 1.33333\n402 688 Line 11.3333 1.33333 12 1.33333\n402 715 Line 11.3333 0.666667 12 0.666667\n403 689 Line 12 1.33333 12.6667 1.33333\n403 716 Line 12 0.666667 12.6667 0.666667\n404 457 Line 8.66667 9.33333 8.66667 10\n404 860 Line 8 9.33333 8.66667 9.33333\n405 406 Line 18.6667 12 18.6667 12.6667\n405 464 Line 18 12 18.6667 12\n406 446 Line 18.6667 12.6667 19.3333 12.6667\n406 453 Line 19.3333 12 19.3333 12.6667\n407 526 Line 9.33333 4.66667 9.33333 5.33333\n407 588 Line 8.66667 4.66667 8.66667 5.33333\n407 646 Line 8.66667 4.66667 9.33333 4.66667\n408 535 Line 4 8.66667 4 9.33333\n408 547 Line 3.33333 9.33333 4 9.33333\n408 699 Line 3.33333 8.66667 3.33333 9.33333\n408 735 Line 3.33333 8.66667 4 8.66667\n409 410 Line 21.3333 11.3333 22 11.3333\n409 459 Line 21.3333 10.6667 21.3333 11.3333\n409 473 Line 21.3333 10.6667 22 10.6667\n411 412 Line 16.6667 13.3333 16.6667 14\n412 578 Line 17.3333 13.3333 17.3333 14\n413 550 Line 3.33333 6.66667 4 6.66667\n413 635 Line 3.33333 6.66667 3.33333 7.33333\n413 734 Line 3.33333 7.33333 4 7.33333\n413 851 Line 4 6.66667 4 7.33333\n414 769 Line 32.6667 9.33333 33.3333 9.33333\n414 888 Line 32.6667 8.66667 32.6667 9.33333\n414 972 Line 32.6667 8.66667 33.3333 8.66667\n415 416 Line 14 12 14.6667 12\n415 553 Line 14 11.3333 14 12\n415 557 Line 14 11.3333 14.6667 11.3333\n415 738 Line 14.6667 11.3333 14.6667 12\n416 568 Line 14 12.6667 14.6667 12.6667\n416 739 Line 14.6667 12 14.6667 12.6667\n417 418 Line 12.6667 4.66667 12.6667 5.33333\n417 524 Line 12 5.33333 12.6667 5.33333\n417 989 Line 12 4.66667 12 5.33333\n418 582 Line 12.6667 4.66667 13.3333 4.66667\n418 714 Line 13.3333 4.66667 13.3333 5.33333\n419 -1 Line 34 14 34 14.6667\n419 487 Line 33.3333 14 34 14\n419 911 Line 33.3333 14.6667 34 14.6667\n420 472 Line 15.3333 5.33333 15.3333 6\n420 607 Line 15.3333 6 16 6\n420 876 Line 16 5.33333 16 6\n421 511 Line 2.66667 16.6667 2.66667 17.3333\n421 690 Line 2 17.3333 2.66667 17.3333\n422 423 Line 12.6667 22 13.3333 22\n423 -1 Line 12.6667 22.6667 13.3333 22.6667\n424 517 Line 9.33333 6 10 6\n424 526 Line 9.33333 5.33333 10 5.33333\n424 595 Line 10 5.33333 10 6\n425 547 Line 3.33333 9.33333 3.33333 10\n425 699 Line 2.66667 9.33333 3.33333 9.33333\n426 702 Line 16 10.6667 16 11.3333\n426 862 Line 15.3333 10.6667 16 10.6667\n427 571 Line 13.3333 2.66667 14 2.66667\n427 753 Line 13.3333 3.33333 14 3.33333\n427 766 Line 14 2.66667 14 3.33333\n428 429 Line 26.6667 6.66667 27.3333 6.66667\n428 451 Line 26.6667 6 27.3333 6\n430 693 Line 24 16 24 16.6667\n430 863 Line 24 16 24.6667 16\n430 922 Line 24 16.6667 24.6667 16.6667\n431 432 Line 8 5.33333 8 6\n431 534 Line 7.33333 6 8 6\n431 587 Line 7.33333 5.33333 8 5.33333\n432 515 Line 8 6 8.66667 6\n432 588 Line 8 5.33333 8.66667 5.33333\n433 434 Line 13.3333 1.33333 13.3333 2\n433 570 Line 12.6667 2 13.3333 2\n433 689 Line 12.6667 1.33333 12.6667 2\n434 571 Line 13.3333 2 14 2\n434 771 Line 14 1.33333 14 2\n435 461 Line 6 11.3333 6 12\n435 479 Line 5.33333 12 6 12\n436 437 Line 25.3333 8 25.3333 8.66667\n437 593 Line 26 8 26 8.66667\n438 620 Line 13.3333 8 14 8\n438 661 Line 13.3333 7.33333 14 7.33333\n439 440 Line 23.3333 9.33333 23.3333 10\n439 469 Line 22.6667 9.33333 22.6667 10\n440 470 Line 23.3333 10 24 10\n440 683 Line 23.3333 9.33333 24 9.33333\n441 442 Line 14.6667 9.33333 14.6667 10\n441 556 Line 14 10 14.6667 10\n441 718 Line 14 9.33333 14.6667 9.33333\n441 762 Line 14 9.33333 14 10\n442 861 Line 15.3333 9.33333 15.3333 10\n444 750 Line 15.3333 14 15.3333 14.6667\n444 909 Line 15.3333 14.6667 16 14.6667\n445 555 Line 12 2.66667 12.6667 2.66667\n445 570 Line 12.6667 2 12.6667 2.66667\n445 689 Line 12 2 12.6667 2\n446 447 Line 18.6667 13.3333 19.3333 13.3333\n446 454 Line 19.3333 12.6667 19.3333 13.3333\n448 449 Line 6.66667 2 6.66667 2.66667\n448 680 Line 6 2.66667 6.66667 2.66667\n448 685 Line 6 2 6 2.66667\n448 761 Line 6 2 6.66667 2\n449 681 Line 6.66667 2.66667 7.33333 2.66667\n450 483 Line 12.6667 14.6667 13.3333 14.6667\n450 501 Line 12.6667 14.6667 12.6667 15.3333\n452 -1 Line 13.3333 0 14 0\n453 454 Line 19.3333 12.6667 20 12.6667\n454 669 Line 20 12.6667 20 13.3333\n455 456 Line 20.6667 10 21.3333 10\n455 468 Line 21.3333 9.33333 21.3333 10\n455 778 Line 20.6667 9.33333 20.6667 10\n455 974 Line 20.6667 9.33333 21.3333 9.33333\n456 459 Line 20.6667 10.6667 21.3333 10.6667\n456 473 Line 21.3333 10 21.3333 10.6667\n456 779 Line 20.6667 10 20.6667 10.6667\n457 546 Line 9.33333 9.33333 9.33333 10\n457 664 Line 8.66667 10 9.33333 10\n457 744 Line 8.66667 9.33333 9.33333 9.33333\n458 459 Line 20.6667 10.6667 20.6667 11.3333\n458 779 Line 20 10.6667 20.6667 10.6667\n460 525 Line 12 6 12 6.66667\n460 708 Line 11.3333 6 11.3333 6.66667\n460 713 Line 11.3333 6 12 6\n460 756 Line 11.3333 6.66667 12 6.66667\n461 490 Line 6 11.3333 6.66667 11.3333\n461 518 Line 6 12 6.66667 12\n462 824 Line 8 10.6667 8 11.3333\n462 960 Line 8.66667 10.6667 8.66667 11.3333\n462 975 Line 8 11.3333 8.66667 11.3333\n463 464 Line 18 11.3333 18 12\n465 466 Line 18 14 18 14.6667\n465 578 Line 17.3333 14 18 14\n467 737 Line 2.66667 15.3333 3.33333 15.3333\n468 469 Line 22 9.33333 22 10\n468 473 Line 21.3333 10 22 10\n469 474 Line 22 10 22.6667 10\n470 471 Line 24 10 24 10.6667\n471 878 Line 24 10.6667 24.6667 10.6667\n472 506 Line 14.6667 5.33333 14.6667 6\n473 474 Line 22 10 22 10.6667\n475 -1 Line 0 14 0 14.6667\n476 692 Line 26.6667 9.33333 27.3333 9.33333\n477 478 Line 23.3333 18 23.3333 18.6667\n477 514 Line 22.6667 18 22.6667 18.6667\n477 657 Line 22.6667 18 23.3333 18\n478 513 Line 23.3333 18 24 18\n479 518 Line 6 12 6 12.6667\n480 481 Line 16.6667 8.66667 17.3333 8.66667\n480 846 Line 16.6667 8 16.6667 8.66667\n481 639 Line 16.6667 9.33333 17.3333 9.33333\n481 847 Line 16.6667 8.66667 16.6667 9.33333\n482 625 Line 9.33333 3.33333 10 3.33333\n482 788 Line 9.33333 2.66667 9.33333 3.33333\n483 484 Line 13.3333 14 13.3333 14.6667\n483 560 Line 12.6667 14 13.3333 14\n483 606 Line 12.6667 14 12.6667 14.6667\n484 591 Line 13.3333 14 14 14\n484 749 Line 14 14 14 14.6667\n485 486 Line 4.66667 4.66667 4.66667 5.33333\n486 782 Line 5.33333 4.66667 5.33333 5.33333\n487 -1 Line 34 13.3333 34 14\n487 924 Line 33.3333 13.3333 34 13.3333\n488 751 Line 17.3333 6 18 6\n488 877 Line 17.3333 5.33333 17.3333 6\n489 554 Line 11.3333 2.66667 11.3333 3.33333\n489 567 Line 10.6667 3.33333 11.3333 3.33333\n490 613 Line 6 10.6667 6.66667 10.6667\n490 823 Line 6.66667 10.6667 6.66667 11.3333\n491 492 Line 22.6667 14 23.3333 14\n491 580 Line 23.3333 13.3333 23.3333 14\n492 678 Line 23.3333 14 23.3333 14.6667\n492 849 Line 22.6667 14.6667 23.3333 14.6667\n493 494 Line 14.6667 3.33333 15.3333 3.33333\n493 539 Line 14.6667 2.66667 15.3333 2.66667\n493 610 Line 15.3333 2.66667 15.3333 3.33333\n493 766 Line 14.6667 2.66667 14.6667 3.33333\n494 767 Line 14.6667 3.33333 14.6667 4\n495 496 Line 28 6.66667 28.6667 6.66667\n495 520 Line 28.6667 6 28.6667 6.66667\n495 564 Line 28 6 28.6667 6\n496 521 Line 28.6667 6.66667 28.6667 7.33333\n496 844 Line 28 7.33333 28.6667 7.33333\n497 516 Line 28.6667 8 29.3333 8\n497 521 Line 28.6667 7.33333 29.3333 7.33333\n497 622 Line 29.3333 7.33333 29.3333 8\n497 844 Line 28.6667 7.33333 28.6667 8\n498 774 Line 10 12 10 12.6667\n499 649 Line 24.6667 11.3333 25.3333 11.3333\n499 878 Line 24.6667 10.6667 24.6667 11.3333\n499 932 Line 25.3333 10.6667 25.3333 11.3333\n500 501 Line 12 14.6667 12 15.3333\n500 605 Line 11.3333 14.6667 12 14.6667\n501 606 Line 12 14.6667 12.6667 14.6667\n503 504 Line 16 10 16.6667 10\n503 639 Line 16.6667 9.33333 16.6667 10\n503 847 Line 16 9.33333 16.6667 9.33333\n503 861 Line 16 9.33333 16 10\n504 640 Line 16.6667 10 16.6667 10.6667\n504 702 Line 16 10.6667 16.6667 10.6667\n504 862 Line 16 10 16 10.6667\n506 541 Line 14 6 14.6667 6\n506 786 Line 14 5.33333 14.6667 5.33333\n507 508 Line 27.3333 4.66667 28 4.66667\n509 510 Line 10.6667 4 10.6667 4.66667\n509 566 Line 10 4 10.6667 4\n509 626 Line 10 4 10 4.66667\n509 976 Line 10 4.66667 10.6667 4.66667\n510 567 Line 10.6667 4 11.3333 4\n510 988 Line 10.6667 4.66667 11.3333 4.66667\n511 867 Line 3.33333 16.6667 3.33333 17.3333\n512 656 Line 22.6667 16.6667 23.3333 16.6667\n512 693 Line 23.3333 16 23.3333 16.6667\n512 850 Line 22.6667 16 23.3333 16\n513 657 Line 23.3333 17.3333 23.3333 18\n513 694 Line 23.3333 17.3333 24 17.3333\n514 558 Line 22 18.6667 22.6667 18.6667\n515 528 Line 8 6.66667 8.66667 6.66667\n515 534 Line 8 6 8 6.66667\n516 845 Line 28.6667 8 28.6667 8.66667\n516 917 Line 28.6667 8.66667 29.3333 8.66667\n517 707 Line 10 6 10 6.66667\n518 519 Line 6.66667 12 6.66667 12.6667\n518 727 Line 6 12.6667 6.66667 12.6667\n519 728 Line 6.66667 12.6667 7.33333 12.6667\n520 521 Line 28.6667 6.66667 29.3333 6.66667\n522 681 Line 7.33333 2.66667 7.33333 3.33333\n522 787 Line 8 2.66667 8 3.33333\n522 816 Line 7.33333 3.33333 8 3.33333\n524 525 Line 12 6 12.6667 6\n524 713 Line 12 5.33333 12 6\n526 626 Line 9.33333 4.66667 10 4.66667\n526 976 Line 10 4.66667 10 5.33333\n527 528 Line 8 6.66667 8 7.33333\n527 534 Line 7.33333 6.66667 8 6.66667\n527 666 Line 7.33333 7.33333 8 7.33333\n528 671 Line 8 7.33333 8.66667 7.33333\n529 990 Line 4.66667 16.6667 5.33333 16.6667\n530 531 Line 7.33333 10 7.33333 10.6667\n530 613 Line 6.66667 10 6.66667 10.6667\n530 823 Line 6.66667 10.6667 7.33333 10.6667\n531 824 Line 7.33333 10.6667 8 10.6667\n532 752 Line 17.3333 7.33333 18 7.33333\n532 896 Line 18 7.33333 18 8\n533 534 Line 7.33333 6 7.33333 6.66667\n533 985 Line 6.66667 6 6.66667 6.66667\n535 616 Line 4 9.33333 4.66667 9.33333\n535 747 Line 4.66667 8.66667 4.66667 9.33333\n535 853 Line 4 8.66667 4.66667 8.66667\n536 -1 Line 34 6.66667 34 7.33333\n536 642 Line 33.3333 6.66667 33.3333 7.33333\n537 629 Line 14 19.3333 14 20\n538 539 Line 14.6667 2 14.6667 2.66667\n538 571 Line 14 2 14 2.66667\n538 766 Line 14 2.66667 14.6667 2.66667\n538 771 Line 14 2 14.6667 2\n539 772 Line 14.6667 2 15.3333 2\n542 543 Line 23.3333 15.3333 24 15.3333\n542 678 Line 23.3333 14.6667 24 14.6667\n542 849 Line 23.3333 14.6667 23.3333 15.3333\n542 865 Line 24 14.6667 24 15.3333\n543 693 Line 23.3333 16 24 16\n543 850 Line 23.3333 15.3333 23.3333 16\n543 863 Line 24 15.3333 24 16\n544 545 Line 10.6667 15.3333 10.6667 16\n546 721 Line 9.33333 9.33333 10 9.33333\n546 740 Line 10 9.33333 10 10\n546 997 Line 9.33333 10 10 10\n547 548 Line 3.33333 10 4 10\n547 616 Line 4 9.33333 4 10\n548 612 Line 4 10 4 10.6667\n549 550 Line 3.33333 6 4 6\n551 552 Line 4.66667 3.33333 4.66667 4\n551 730 Line 4 3.33333 4.66667 3.33333\n552 731 Line 4.66667 3.33333 5.33333 3.33333\n554 555 Line 12 2.66667 12 3.33333\n554 965 Line 11.3333 3.33333 12 3.33333\n555 966 Line 12 3.33333 12.6667 3.33333\n556 557 Line 14 10.6667 14.6667 10.6667\n558 872 Line 22 19.3333 22.6667 19.3333\n559 560 Line 12.6667 13.3333 13.3333 13.3333\n559 562 Line 13.3333 12.6667 13.3333 13.3333\n559 609 Line 12.6667 12.6667 13.3333 12.6667\n560 591 Line 13.3333 13.3333 13.3333 14\n560 811 Line 12.6667 13.3333 12.6667 14\n561 569 Line 14.6667 13.3333 15.3333 13.3333\n561 592 Line 14.6667 13.3333 14.6667 14\n561 750 Line 14.6667 14 15.3333 14\n562 568 Line 14 12.6667 14 13.3333\n562 591 Line 13.3333 13.3333 14 13.3333\n563 587 Line 7.33333 4.66667 7.33333 5.33333\n563 783 Line 6.66667 4.66667 6.66667 5.33333\n563 831 Line 6.66667 4.66667 7.33333 4.66667\n565 -1 Line 26 22.6667 26.6667 22.6667\n565 835 Line 26 22 26 22.6667\n566 567 Line 10.6667 3.33333 10.6667 4\n566 625 Line 10 3.33333 10 4\n567 965 Line 11.3333 3.33333 11.3333 4\n568 569 Line 14.6667 12.6667 14.6667 13.3333\n568 592 Line 14 13.3333 14.6667 13.3333\n569 739 Line 14.6667 12.6667 15.3333 12.6667\n570 571 Line 13.3333 2 13.3333 2.66667\n572 573 Line 20.6667 12.6667 21.3333 12.6667\n573 627 Line 20.6667 13.3333 21.3333 13.3333\n573 669 Line 20.6667 12.6667 20.6667 13.3333\n573 773 Line 21.3333 12.6667 21.3333 13.3333\n574 575 Line 4.66667 10.6667 4.66667 11.3333\n574 612 Line 4 10.6667 4.66667 10.6667\n575 757 Line 4.66667 10.6667 5.33333 10.6667\n576 618 Line 26 2.66667 26 3.33333\n576 821 Line 26 3.33333 26.6667 3.33333\n576 962 Line 26 2.66667 26.6667 2.66667\n577 578 Line 17.3333 13.3333 18 13.3333\n579 580 Line 23.3333 13.3333 24 13.3333\n579 939 Line 24 12.6667 24 13.3333\n579 986 Line 23.3333 12.6667 24 12.6667\n580 678 Line 23.3333 14 24 14\n580 940 Line 24 13.3333 24 14\n581 582 Line 12.6667 4 13.3333 4\n581 753 Line 13.3333 3.33333 13.3333 4\n581 966 Line 12.6667 3.33333 12.6667 4\n582 754 Line 13.3333 4 13.3333 4.66667\n583 584 Line 30.6667 5.33333 30.6667 6\n583 884 Line 30 5.33333 30.6667 5.33333\n584 604 Line 30.6667 5.33333 31.3333 5.33333\n585 586 Line 6 17.3333 6 18\n586 894 Line 6.66667 17.3333 6.66667 18\n587 588 Line 8 4.66667 8 5.33333\n589 590 Line 7.33333 8.66667 7.33333 9.33333\n589 601 Line 6.66667 8.66667 7.33333 8.66667\n590 602 Line 7.33333 8.66667 8 8.66667\n590 860 Line 8 8.66667 8 9.33333\n591 592 Line 14 13.3333 14 14\n592 749 Line 14 14 14.6667 14\n593 594 Line 26 8.66667 26.6667 8.66667\n593 691 Line 26.6667 8 26.6667 8.66667\n594 692 Line 26.6667 8.66667 26.6667 9.33333\n595 707 Line 10 6 10.6667 6\n595 712 Line 10.6667 5.33333 10.6667 6\n595 976 Line 10 5.33333 10.6667 5.33333\n596 597 Line 2 8 2.66667 8\n596 807 Line 2 7.33333 2.66667 7.33333\n597 698 Line 2.66667 8 2.66667 8.66667\n598 -1 Line 0 2 0 2.66667\n598 599 Line 0.666667 2 0.666667 2.66667\n599 977 Line 0.666667 2.66667 1.33333 2.66667\n600 980 Line 1.33333 4.66667 1.33333 5.33333\n601 602 Line 7.33333 8 7.33333 8.66667\n601 665 Line 6.66667 8 7.33333 8\n602 666 Line 7.33333 8 8 8\n602 859 Line 8 8 8 8.66667\n603 604 Line 30.6667 4.66667 31.3333 4.66667\n603 854 Line 31.3333 4 31.3333 4.66667\n603 883 Line 30.6667 4 30.6667 4.66667\n604 884 Line 30.6667 4.66667 30.6667 5.33333\n605 606 Line 12 14 12 14.6667\n606 811 Line 12 14 12.6667 14\n607 874 Line 15.3333 6.66667 16 6.66667\n608 609 Line 12.6667 12 12.6667 12.6667\n610 611 Line 16 2.66667 16 3.33333\n611 662 Line 16 3.33333 16.6667 3.33333\n612 616 Line 4 10 4.66667 10\n612 757 Line 4.66667 10 4.66667 10.6667\n613 617 Line 6 10 6.66667 10\n613 758 Line 6 10 6 10.6667\n615 644 Line 28 9.33333 28.6667 9.33333\n615 845 Line 28 8.66667 28.6667 8.66667\n615 917 Line 28.6667 8.66667 28.6667 9.33333\n616 654 Line 4.66667 9.33333 4.66667 10\n617 655 Line 6 9.33333 6 10\n618 619 Line 25.3333 2.66667 26 2.66667\n618 760 Line 25.3333 2.66667 25.3333 3.33333\n618 819 Line 25.3333 3.33333 26 3.33333\n619 704 Line 25.3333 2 26 2\n619 962 Line 26 2 26 2.66667\n620 621 Line 13.3333 8.66667 14 8.66667\n620 781 Line 13.3333 8 13.3333 8.66667\n620 949 Line 14 8 14 8.66667\n621 718 Line 14 8.66667 14 9.33333\n621 762 Line 13.3333 9.33333 14 9.33333\n622 623 Line 30 7.33333 30 8\n624 -1 Line 2.66667 0 3.33333 0\n625 626 Line 9.33333 4 10 4\n625 645 Line 9.33333 3.33333 9.33333 4\n626 646 Line 9.33333 4 9.33333 4.66667\n627 628 Line 20.6667 14 21.3333 14\n627 670 Line 20.6667 13.3333 20.6667 14\n629 630 Line 14.6667 19.3333 14.6667 20\n631 -1 Line 28.6667 0 29.3333 0\n632 633 Line 30.6667 11.3333 30.6667 12\n632 826 Line 30 11.3333 30 12\n632 938 Line 30 11.3333 30.6667 11.3333\n633 921 Line 30.6667 11.3333 31.3333 11.3333\n635 807 Line 2.66667 6.66667 2.66667 7.33333\n636 977 Line 1.33333 2.66667 1.33333 3.33333\n637 -1 Line 18.6667 22.6667 19.3333 22.6667\n637 951 Line 18.6667 22 19.3333 22\n638 986 Line 23.3333 12 23.3333 12.6667\n639 640 Line 16.6667 10 17.3333 10\n639 998 Line 17.3333 9.33333 17.3333 10\n640 703 Line 16.6667 10.6667 17.3333 10.6667\n641 697 Line 20 16 20 16.6667\n641 919 Line 19.3333 16 20 16\n642 971 Line 32.6667 7.33333 33.3333 7.33333\n643 -1 Line 24.6667 0 25.3333 0\n643 705 Line 25.3333 0 25.3333 0.666667\n643 943 Line 24.6667 0.666667 25.3333 0.666667\n644 904 Line 28 10 28.6667 10\n645 646 Line 8.66667 4 9.33333 4\n645 788 Line 8.66667 3.33333 9.33333 3.33333\n645 817 Line 8.66667 3.33333 8.66667 4\n647 648 Line 8 16.6667 8 17.3333\n647 658 Line 7.33333 16.6667 7.33333 17.3333\n647 895 Line 7.33333 17.3333 8 17.3333\n648 893 Line 8 17.3333 8.66667 17.3333\n649 650 Line 24.6667 12 25.3333 12\n649 879 Line 24.6667 11.3333 24.6667 12\n649 933 Line 25.3333 11.3333 25.3333 12\n650 759 Line 24.6667 12.6667 25.3333 12.6667\n650 889 Line 25.3333 12 25.3333 12.6667\n650 987 Line 24.6667 12 24.6667 12.6667\n651 671 Line 8.66667 7.33333 8.66667 8\n651 743 Line 8.66667 8 9.33333 8\n651 926 Line 9.33333 7.33333 9.33333 8\n652 653 Line 32 9.33333 32 10\n653 769 Line 32.6667 9.33333 32.6667 10\n653 888 Line 32 9.33333 32.6667 9.33333\n654 655 Line 5.33333 9.33333 5.33333 10\n654 747 Line 4.66667 9.33333 5.33333 9.33333\n654 757 Line 4.66667 10 5.33333 10\n655 748 Line 5.33333 9.33333 6 9.33333\n655 758 Line 5.33333 10 6 10\n656 657 Line 22.6667 17.3333 23.3333 17.3333\n656 694 Line 23.3333 16.6667 23.3333 17.3333\n658 792 Line 6.66667 16.6667 7.33333 16.6667\n658 894 Line 6.66667 17.3333 7.33333 17.3333\n659 660 Line 32.6667 11.3333 33.3333 11.3333\n659 770 Line 32.6667 10.6667 33.3333 10.6667\n660 908 Line 33.3333 11.3333 33.3333 12\n662 663 Line 16 4 16.6667 4\n662 722 Line 16.6667 3.33333 16.6667 4\n663 676 Line 16.6667 4 16.6667 4.66667\n664 960 Line 8.66667 10.6667 9.33333 10.6667\n664 997 Line 9.33333 10 9.33333 10.6667\n665 666 Line 7.33333 7.33333 7.33333 8\n666 671 Line 8 7.33333 8 8\n667 668 Line 10 8.66667 10.6667 8.66667\n667 672 Line 10.6667 8 10.6667 8.66667\n667 720 Line 10 8 10 8.66667\n667 927 Line 10 8 10.6667 8\n668 721 Line 10 8.66667 10 9.33333\n668 725 Line 10.6667 8.66667 10.6667 9.33333\n668 740 Line 10 9.33333 10.6667 9.33333\n669 670 Line 20 13.3333 20.6667 13.3333\n671 859 Line 8 8 8.66667 8\n672 673 Line 11.3333 8 11.3333 8.66667\n672 725 Line 10.6667 8.66667 11.3333 8.66667\n672 928 Line 10.6667 8 11.3333 8\n673 726 Line 11.3333 8.66667 12 8.66667\n673 755 Line 11.3333 8 12 8\n673 780 Line 12 8 12 8.66667\n674 675 Line 19.3333 4.66667 19.3333 5.33333\n675 838 Line 20 4.66667 20 5.33333\n675 969 Line 19.3333 5.33333 20 5.33333\n676 677 Line 16.6667 4.66667 17.3333 4.66667\n676 722 Line 16.6667 4 17.3333 4\n676 808 Line 17.3333 4 17.3333 4.66667\n677 877 Line 16.6667 5.33333 17.3333 5.33333\n678 679 Line 24 14 24 14.6667\n679 764 Line 24.6667 14 24.6667 14.6667\n679 865 Line 24 14.6667 24.6667 14.6667\n679 940 Line 24 14 24.6667 14\n680 681 Line 6.66667 2.66667 6.66667 3.33333\n681 830 Line 6.66667 3.33333 7.33333 3.33333\n682 683 Line 23.3333 8.66667 24 8.66667\n684 685 Line 5.33333 2 5.33333 2.66667\n684 687 Line 4.66667 2 4.66667 2.66667\n684 731 Line 4.66667 2.66667 5.33333 2.66667\n686 687 Line 4 2 4 2.66667\n687 730 Line 4 2.66667 4.66667 2.66667\n688 689 Line 12 1.33333 12 2\n688 742 Line 11.3333 1.33333 11.3333 2\n691 692 Line 26.6667 8.66667 27.3333 8.66667\n693 694 Line 23.3333 16.6667 24 16.6667\n694 922 Line 24 16.6667 24 17.3333\n695 696 Line 21.3333 15.3333 22 15.3333\n697 945 Line 20 16 20.6667 16\n698 699 Line 2.66667 8.66667 3.33333 8.66667\n698 735 Line 3.33333 8 3.33333 8.66667\n700 701 Line 4 12.6667 4 13.3333\n700 806 Line 3.33333 12.6667 4 12.6667\n700 953 Line 3.33333 12.6667 3.33333 13.3333\n702 703 Line 16.6667 10.6667 16.6667 11.3333\n704 706 Line 25.3333 1.33333 26 1.33333\n704 961 Line 26 1.33333 26 2\n705 -1 Line 25.3333 0 26 0\n705 706 Line 25.3333 0.666667 26 0.666667\n706 943 Line 25.3333 0.666667 25.3333 1.33333\n707 708 Line 10.6667 6 10.6667 6.66667\n708 712 Line 10.6667 6 11.3333 6\n708 887 Line 10.6667 6.66667 11.3333 6.66667\n709 710 Line 16 1.33333 16 2\n709 772 Line 15.3333 1.33333 15.3333 2\n710 957 Line 16.6667 1.33333 16.6667 2\n712 713 Line 11.3333 5.33333 11.3333 6\n712 988 Line 10.6667 5.33333 11.3333 5.33333\n713 989 Line 11.3333 5.33333 12 5.33333\n714 754 Line 13.3333 4.66667 14 4.66667\n714 786 Line 14 4.66667 14 5.33333\n715 -1 Line 11.3333 0 12 0\n715 716 Line 12 0 12 0.666667\n716 -1 Line 12 0 12.6667 0\n717 959 Line 29.3333 12.6667 30 12.6667\n718 949 Line 14 8.66667 14.6667 8.66667\n719 -1 Line 0 6.66667 0 7.33333\n719 775 Line 0 7.33333 0.666667 7.33333\n720 721 Line 9.33333 8.66667 10 8.66667\n720 743 Line 9.33333 8 9.33333 8.66667\n720 926 Line 9.33333 8 10 8\n721 744 Line 9.33333 8.66667 9.33333 9.33333\n723 -1 Line 16.6667 0 17.3333 0\n723 724 Line 16.6667 0.666667 17.3333 0.666667\n724 957 Line 16.6667 1.33333 17.3333 1.33333\n725 726 Line 11.3333 8.66667 11.3333 9.33333\n727 728 Line 6.66667 12.6667 6.66667 13.3333\n727 784 Line 6 13.3333 6.66667 13.3333\n728 729 Line 7.33333 12.6667 7.33333 13.3333\n730 731 Line 4.66667 2.66667 4.66667 3.33333\n732 733 Line 25.3333 6.66667 25.3333 7.33333\n734 735 Line 3.33333 8 4 8\n734 852 Line 4 7.33333 4 8\n735 853 Line 4 8 4 8.66667\n736 772 Line 14.6667 1.33333 15.3333 1.33333\n738 739 Line 14.6667 12 15.3333 12\n740 741 Line 10 10 10.6667 10\n741 841 Line 10.6667 10 10.6667 10.6667\n741 997 Line 10 10 10 10.6667\n743 744 Line 8.66667 8.66667 9.33333 8.66667\n743 859 Line 8.66667 8 8.66667 8.66667\n744 860 Line 8.66667 8.66667 8.66667 9.33333\n745 746 Line 16.6667 6.66667 17.3333 6.66667\n745 751 Line 17.3333 6 17.3333 6.66667\n745 877 Line 16.6667 6 17.3333 6\n746 752 Line 17.3333 6.66667 17.3333 7.33333\n747 748 Line 5.33333 8.66667 5.33333 9.33333\n749 750 Line 14.6667 14 14.6667 14.6667\n750 942 Line 14.6667 14.6667 15.3333 14.6667\n751 752 Line 17.3333 6.66667 18 6.66667\n751 897 Line 18 6 18 6.66667\n752 898 Line 18 6.66667 18 7.33333\n753 754 Line 13.3333 4 14 4\n753 767 Line 14 3.33333 14 4\n754 785 Line 14 4 14 4.66667\n755 756 Line 11.3333 7.33333 12 7.33333\n755 928 Line 11.3333 7.33333 11.3333 8\n756 887 Line 11.3333 6.66667 11.3333 7.33333\n757 758 Line 5.33333 10 5.33333 10.6667\n759 848 Line 24.6667 13.3333 25.3333 13.3333\n759 939 Line 24.6667 12.6667 24.6667 13.3333\n760 799 Line 24.6667 3.33333 25.3333 3.33333\n762 946 Line 13.3333 9.33333 13.3333 10\n763 765 Line 26 14 26 14.6667\n764 765 Line 25.3333 14 25.3333 14.6667\n764 848 Line 24.6667 14 25.3333 14\n764 866 Line 24.6667 14.6667 25.3333 14.6667\n766 767 Line 14 3.33333 14.6667 3.33333\n767 785 Line 14 4 14.6667 4\n769 770 Line 32.6667 10 33.3333 10\n771 772 Line 14.6667 1.33333 14.6667 2\n775 -1 Line 0 7.33333 0 8\n776 777 Line 1.33333 12.6667 1.33333 13.3333\n778 779 Line 20 10 20.6667 10\n778 973 Line 20 9.33333 20.6667 9.33333\n778 982 Line 20 9.33333 20 10\n779 983 Line 20 10 20 10.6667\n780 781 Line 12.6667 8 12.6667 8.66667\n782 783 Line 6 4.66667 6 5.33333\n782 801 Line 5.33333 4.66667 6 4.66667\n783 802 Line 6 4.66667 6.66667 4.66667\n785 786 Line 14 4.66667 14.6667 4.66667\n787 788 Line 8.66667 2.66667 8.66667 3.33333\n787 817 Line 8 3.33333 8.66667 3.33333\n789 934 Line 22 6.66667 22.6667 6.66667\n789 958 Line 22 6 22.6667 6\n790 -1 Line 34 4 34 4.66667\n790 791 Line 33.3333 4.66667 34 4.66667\n790 839 Line 33.3333 4 33.3333 4.66667\n791 -1 Line 34 4.66667 34 5.33333\n791 840 Line 33.3333 4.66667 33.3333 5.33333\n793 794 Line 18.6667 10.6667 19.3333 10.6667\n793 983 Line 19.3333 10 19.3333 10.6667\n795 796 Line 20.6667 22 21.3333 22\n795 996 Line 21.3333 21.3333 21.3333 22\n796 -1 Line 20.6667 22.6667 21.3333 22.6667\n798 800 Line 24.6667 4.66667 25.3333 4.66667\n798 803 Line 25.3333 4.66667 25.3333 5.33333\n798 857 Line 24.6667 4.66667 24.6667 5.33333\n799 800 Line 24.6667 4 25.3333 4\n799 819 Line 25.3333 3.33333 25.3333 4\n800 820 Line 25.3333 4 25.3333 4.66667\n800 858 Line 24.6667 4 24.6667 4.66667\n801 802 Line 6 4 6 4.66667\n802 831 Line 6.66667 4 6.66667 4.66667\n803 804 Line 26 4.66667 26 5.33333\n803 820 Line 25.3333 4.66667 26 4.66667\n804 822 Line 26 4.66667 26.6667 4.66667\n805 806 Line 3.33333 12 4 12\n806 952 Line 3.33333 12 3.33333 12.6667\n807 903 Line 2 6.66667 2.66667 6.66667\n808 809 Line 18 4 18 4.66667\n814 815 Line 27.3333 0.666667 27.3333 1.33333\n816 817 Line 8 3.33333 8 4\n816 830 Line 7.33333 3.33333 7.33333 4\n819 820 Line 25.3333 4 26 4\n819 821 Line 26 3.33333 26 4\n820 822 Line 26 4 26 4.66667\n821 822 Line 26 4 26.6667 4\n823 824 Line 7.33333 10.6667 7.33333 11.3333\n825 826 Line 29.3333 11.3333 29.3333 12\n826 959 Line 29.3333 12 30 12\n827 -1 Line 32 22.6667 32.6667 22.6667\n827 828 Line 32.6667 22 32.6667 22.6667\n827 829 Line 32 22 32 22.6667\n828 -1 Line 32.6667 22.6667 33.3333 22.6667\n828 836 Line 33.3333 22 33.3333 22.6667\n829 -1 Line 31.3333 22.6667 32 22.6667\n830 831 Line 6.66667 4 7.33333 4\n832 833 Line 25.3333 21.3333 25.3333 22\n832 834 Line 24.6667 22 25.3333 22\n832 995 Line 24.6667 21.3333 24.6667 22\n833 835 Line 25.3333 22 26 22\n834 -1 Line 24.6667 22.6667 25.3333 22.6667\n834 835 Line 25.3333 22 25.3333 22.6667\n835 -1 Line 25.3333 22.6667 26 22.6667\n836 -1 Line 33.3333 22.6667 34 22.6667\n836 882 Line 33.3333 22 34 22\n837 838 Line 20 4.66667 20.6667 4.66667\n838 970 Line 20 5.33333 20.6667 5.33333\n839 840 Line 32.6667 4.66667 33.3333 4.66667\n839 855 Line 32.6667 4 32.6667 4.66667\n841 842 Line 11.3333 10 11.3333 10.6667\n842 936 Line 12 10 12 10.6667\n843 885 Line 29.3333 4 30 4\n844 845 Line 28 8 28.6667 8\n846 847 Line 16 8.66667 16.6667 8.66667\n846 905 Line 16 8 16 8.66667\n847 906 Line 16 8.66667 16 9.33333\n848 940 Line 24.6667 13.3333 24.6667 14\n849 850 Line 22.6667 15.3333 23.3333 15.3333\n851 852 Line 4 7.33333 4.66667 7.33333\n852 853 Line 4 8 4.66667 8\n854 855 Line 32 4 32 4.66667\n856 857 Line 24 4.66667 24 5.33333\n856 984 Line 23.3333 4.66667 23.3333 5.33333\n857 858 Line 24 4.66667 24.6667 4.66667\n859 860 Line 8 8.66667 8.66667 8.66667\n861 862 Line 15.3333 10 16 10\n861 906 Line 15.3333 9.33333 16 9.33333\n863 864 Line 24.6667 15.3333 24.6667 16\n863 865 Line 24 15.3333 24.6667 15.3333\n864 866 Line 24.6667 15.3333 25.3333 15.3333\n865 866 Line 24.6667 14.6667 24.6667 15.3333\n867 868 Line 4 16.6667 4 17.3333\n868 990 Line 4.66667 16.6667 4.66667 17.3333\n870 892 Line 32.6667 15.3333 32.6667 16\n871 880 Line 21.3333 5.33333 21.3333 6\n871 970 Line 20.6667 5.33333 20.6667 6\n872 873 Line 22 20 22.6667 20\n874 875 Line 15.3333 7.33333 16 7.33333\n875 905 Line 15.3333 8 16 8\n876 877 Line 16.6667 5.33333 16.6667 6\n878 879 Line 24 11.3333 24.6667 11.3333\n879 987 Line 24 12 24.6667 12\n880 958 Line 22 5.33333 22 6\n881 -1 Line 34 20.6667 34 21.3333\n881 882 Line 33.3333 21.3333 34 21.3333\n882 -1 Line 34 21.3333 34 22\n883 884 Line 30 4.66667 30.6667 4.66667\n883 885 Line 30 4 30 4.66667\n884 886 Line 30 4.66667 30 5.33333\n885 886 Line 29.3333 4.66667 30 4.66667\n887 928 Line 10.6667 7.33333 11.3333 7.33333\n889 890 Line 26 12 26 12.6667\n889 933 Line 25.3333 12 26 12\n890 931 Line 26 12 26.6667 12\n891 892 Line 32.6667 15.3333 33.3333 15.3333\n891 911 Line 33.3333 14.6667 33.3333 15.3333\n892 912 Line 33.3333 15.3333 33.3333 16\n893 895 Line 8 17.3333 8 18\n894 895 Line 7.33333 17.3333 7.33333 18\n896 898 Line 18 7.33333 18.6667 7.33333\n897 898 Line 18 6.66667 18.6667 6.66667\n899 900 Line 8.66667 14 9.33333 14\n901 918 Line 19.3333 14.6667 19.3333 15.3333\n902 903 Line 2 6 2.66667 6\n904 963 Line 28 10 28 10.6667\n905 906 Line 15.3333 8.66667 16 8.66667\n907 -1 Line 0 20 0 20.6667\n908 -1 Line 34 11.3333 34 12\n908 923 Line 33.3333 12 34 12\n909 910 Line 15.3333 15.3333 16 15.3333\n909 942 Line 15.3333 14.6667 15.3333 15.3333\n911 -1 Line 34 14.6667 34 15.3333\n911 912 Line 33.3333 15.3333 34 15.3333\n912 -1 Line 34 15.3333 34 16\n913 914 Line 16.6667 12 16.6667 12.6667\n915 916 Line 28.6667 2.66667 29.3333 2.66667\n918 919 Line 19.3333 15.3333 20 15.3333\n918 944 Line 20 14.6667 20 15.3333\n919 945 Line 20 15.3333 20 16\n920 921 Line 30.6667 10.6667 31.3333 10.6667\n920 937 Line 30.6667 10 30.6667 10.6667\n921 938 Line 30.6667 10.6667 30.6667 11.3333\n923 -1 Line 34 12 34 12.6667\n923 924 Line 33.3333 12.6667 34 12.6667\n924 -1 Line 34 12.6667 34 13.3333\n926 927 Line 10 7.33333 10 8\n927 928 Line 10.6667 7.33333 10.6667 8\n930 931 Line 26 11.3333 26.6667 11.3333\n930 932 Line 26 10.6667 26 11.3333\n931 933 Line 26 11.3333 26 12\n932 933 Line 25.3333 11.3333 26 11.3333\n935 936 Line 12 10 12.6667 10\n935 946 Line 12.6667 9.33333 12.6667 10\n936 947 Line 12.6667 10 12.6667 10.6667\n937 938 Line 30 10.6667 30.6667 10.6667\n939 940 Line 24 13.3333 24.6667 13.3333\n939 987 Line 24 12.6667 24.6667 12.6667\n944 945 Line 20 15.3333 20.6667 15.3333\n946 947 Line 12.6667 10 13.3333 10\n950 951 Line 18.6667 21.3333 19.3333 21.3333\n952 953 Line 2.66667 12.6667 3.33333 12.6667\n955 956 Line 10 14 10.6667 14\n961 962 Line 26 2 26.6667 2\n963 964 Line 27.3333 10.6667 28 10.6667\n965 966 Line 12 3.33333 12 4\n967 968 Line 27.3333 12.6667 27.3333 13.3333\n969 970 Line 20 5.33333 20 6\n971 972 Line 32.6667 8 33.3333 8\n973 974 Line 20.6667 8.66667 20.6667 9.33333\n976 988 Line 10.6667 4.66667 10.6667 5.33333\n977 978 Line 0.666667 3.33333 1.33333 3.33333\n978 979 Line 0.666667 4 1.33333 4\n979 980 Line 0.666667 4.66667 1.33333 4.66667\n982 983 Line 19.3333 10 20 10\n986 987 Line 24 12 24 12.6667\n988 989 Line 11.3333 4.66667 11.3333 5.33333\n991 992 Line 0.666667 10 1.33333 10\n993 -1 Line 4 0 4.66667 0\n993 994 Line 4 0.666667 4.66667 0.666667\n999 1000 Line 11.3333 11.3333 11.3333 12\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/breadthfirstsearch.h",
    "content": "#ifndef BREADTHFIRSTSEARCH_H\n#define BREADTHFIRSTSEARCH_H\n\n#include \"spanningtreealgorithm.h\"\n#include <vector>\n\nclass BreadthFirstSearch : public SpanningtreeAlgorithm {\n public:\n  std::vector<std::pair<int, int>> SpanningTree(int, const Graph&);\n\n private:\n  std::vector<bool> visited;\n  std::vector<int> currentlevel, nextlevel;\n};\n\n#endif /* end of include guard: BREADTHFIRSTSEARCH_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/cellborder.h",
    "content": "#ifndef CELLBORDER_H\n#define CELLBORDER_H\n\n#include <tuple>\n#include <string>\n\n\nclass CellBorder {\n public:\n  virtual ~CellBorder() = default;\n  virtual std::string GnuplotPrintString() const = 0;\n  virtual std::string SVGPrintString() const = 0;\n};\n\nclass LineBorder : public CellBorder {\npublic:\n    std::string GnuplotPrintString() const override;\n    std::string SVGPrintString() const override;\n    LineBorder(double, double, double, double);\n    explicit LineBorder(std::tuple<double, double, double, double>);\n\n    [[nodiscard]] std::tuple<double, double, double, double> getBorderCoords() const\n    {\n        return std::make_tuple(x1_, y1_, x2_, y2_);\n    }\n\nprotected:\n  double x1_, y1_, x2_, y2_;\n};\n\nclass ArcBorder : public CellBorder {\n public:\n  std::string GnuplotPrintString() const override;\n  std::string SVGPrintString() const override;\n  ArcBorder(double, double, double, double, double);\n\n protected:\n  double cx_, cy_, r_, theta1_, theta2_;\n};\n\n#endif /* end of include guard: CELLBORDER_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/circularhexagonmaze.h",
    "content": "#ifndef CIRCULARHEXAGONMAZE_H\n#define CIRCULARHEXAGONMAZE_H\n\n#include \"hexagonalmaze.h\"\n\nclass CircularHexagonMaze : public HexagonalMaze {\npublic:\n    explicit CircularHexagonMaze(int);\n\nprotected:\n    std::shared_ptr<CellBorder> GetEdge(int, int, int, int) const override;\n    std::tuple<double, double, double, double> GetCoordinateBounds() const override;\n};\n\n#endif /* end of include guard: CIRCULARHEXAGONMAZE_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/circularmaze.h",
    "content": "#ifndef CIRCULARMAZE_H\n#define CIRCULARMAZE_H\n\n#include \"maze.h\"\n\nclass CircularMaze : public Maze {\n public:\n  CircularMaze(int);\n  virtual void InitialiseGraph();\n\n protected:\n  int size_;\n  std::vector<int> ringnodecount_, ringnodeprefixsum_;\n\n  std::tuple<double, double, double, double> GetCoordinateBounds() const;\n};\n\n#endif /* end of include guard: CIRCULARMAZE_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/depthfirstsearch.h",
    "content": "#ifndef DEPTHFIRSTSEARCH_H\n#define DEPTHFIRSTSEARCH_H\n\n#include \"spanningtreealgorithm.h\"\n#include <vector>\n\nclass DepthFirstSearch : public SpanningtreeAlgorithm {\n public:\n  std::vector<std::pair<int, int>> SpanningTree(int, const Graph &);\n\n private:\n  std::vector<bool> visited;\n  void DFS(int, const Graph &);\n};\n\n#endif /* end of include guard: DEPTHFIRSTSEARCH_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/hexagonalmaze.h",
    "content": "#ifndef HEXAGONALMAZE_H\n#define HEXAGONALMAZE_H\n\n#include \"maze.h\"\n\nclass HexagonalMaze : public Maze {\n public:\n  explicit HexagonalMaze(int);\n  void InitialiseGraph() override;\n\n protected:\n  int size_;\n\n  virtual std::shared_ptr<CellBorder> GetEdge(int, int, int, int) const;\n  int VertexIndex(int, int, int, int) const;\n  std::tuple<double, double, double, double> GetCoordinateBounds() const override;\n};\n\n#endif /* end of include guard: HEXAGONALMAZE_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/honeycombmaze.h",
    "content": "#ifndef HONEYCOMBMAZE_H\n#define HONEYCOMBMAZE_H\n\n#include \"maze.h\"\n\nclass HoneyCombMaze : public Maze {\n public:\n  explicit HoneyCombMaze(int);\n  void InitialiseGraph() override;\n\n  std::tuple<double, double, double, double> GetCoordinateBounds() const override;\n\npublic:\n    bool bordersForEntranceAndExit = true;\n\nprotected:\n    int size_;\n    static const int neigh[6][2];\n\n    [[nodiscard]] int VertexIndex(int, int) const;\n    [[nodiscard]] virtual std::tuple<double, double, double, double> GetEdge(int, int, int) const;\n\n    [[nodiscard]] static std::pair<double, double> GetCenter(int u, int v) ;\n\n    std::pair<int, int> VExtent(int);\n\n    bool IsValidNode(int, int);\n};\n\n#endif /* end of include guard: HONEYCOMBMAZE_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/kruskal.h",
    "content": "#ifndef KRUSKAL_H\n#define KRUSKAL_H\n\n#include \"spanningtreealgorithm.h\"\n#include <vector>\n\nclass Kruskal : public SpanningtreeAlgorithm {\n public:\n  std::vector<std::pair<int, int>> SpanningTree(int, const Graph&);\n\n private:\n  std::vector<int> parent_;\n\n  int GetParent(int);\n};\n\n#endif /* end of include guard: KRUSKAL_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/looperasedrandomwalk.h",
    "content": "#ifndef LOOPERASEDRANDOMWALK_H\n#define LOOPERASEDRANDOMWALK_H\n\n#include \"spanningtreealgorithm.h\"\n#include <vector>\n\nclass LoopErasedRandomWalk : public SpanningtreeAlgorithm {\n public:\n  std::vector<std::pair<int, int>> SpanningTree(int, const Graph &);\n\n private:\n  std::vector<int> visited;\n  void LERW(int, int, const Graph &);\n};\n\n#endif /* end of include guard: LOOPERASEDRANDOMWALK_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/maze.h",
    "content": "#ifndef MAZE_H\n#define MAZE_H\n\n#include \"cellborder.h\"\n#include \"spanningtreealgorithm.h\"\n#include <memory>\n#include <vector>\n\n\nusing AdjList = std::vector<std::vector<std::pair<int, std::shared_ptr<CellBorder>>>>;\n\nclass Maze {\n public:\n  explicit Maze(int = 0, int = 0, int = 1);\n  virtual ~Maze() = default;\n  void GenerateMaze(SpanningtreeAlgorithm*);\n  void PrintMazeGnuplot(const std::string&) const;\n  void PrintMazeSVG(const std::string&) const;\n  void RemoveBorders(const std::vector<std::pair<int, int>>&);\n  virtual void InitialiseGraph() = 0;\n\n  AdjList & getAdjacencyList() { return adjacencylist_; }\n  std::vector<std::pair<double, double>> & getCellCenters() { return cellCenters; }\n\n  virtual std::tuple<double, double, double, double> GetCoordinateBounds() const = 0;\n\nprotected:\n    // Solving a maze is equivalent to finding a path in a graph\n    int vertices_;\n    AdjList adjacencylist_;\n    int startvertex_, endvertex_;\n    std::vector<std::pair<double, double>> cellCenters;\n};\n\n#endif /* end of include guard: MAZE_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/prim.h",
    "content": "#ifndef PRIM_H\n#define PRIM_H\n\n#include \"spanningtreealgorithm.h\"\n#include <vector>\n\nclass Prim : public SpanningtreeAlgorithm {\n public:\n  std::vector<std::pair<int, int>> SpanningTree(int, const Graph &);\n\n private:\n  void PrimAlgorithm(int, const Graph &);\n};\n\n#endif /* end of include guard: PRIM_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/rectangularmaze.h",
    "content": "#include \"maze.h\"\n\nclass RectangularMaze : public Maze {\npublic:\n    RectangularMaze(int, int);\n    void InitialiseGraph() override;\n\nprivate:\n    int width_, height_;\n\n    int VertexIndex(int, int);\n    std::tuple<double, double, double, double> GetCoordinateBounds() const override;\n};\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/spanningtreealgorithm.h",
    "content": "#ifndef SPANNINGTREEALGORITHM_H\n#define SPANNINGTREEALGORITHM_H\n\n#include \"cellborder.h\"\n#include <memory>\n#include <random>\n#include <vector>\n\ntypedef std::vector<std::vector<std::pair<int, std::shared_ptr<CellBorder>>>>\n    Graph;\n\nclass SpanningtreeAlgorithm {\n public:\n  SpanningtreeAlgorithm();\n  virtual std::vector<std::pair<int, int>> SpanningTree(int, const Graph&) = 0;\n\n protected:\n  std::vector<std::pair<int, int>> spanningtree;\n  std::random_device randomdevice;\n  std::mt19937 generator;\n};\n\n#endif /* end of include guard: SPANNINGTREEALGORITHM_H */\n"
  },
  {
    "path": "src/libs/mazes/include/mazes/usermaze.h",
    "content": "#include \"maze.h\"\n\nclass UserMaze : public Maze {\n public:\n  UserMaze(std::string);\n  virtual void InitialiseGraph();\n\n private:\n  double xmin_, ymin_, xmax_, ymax_;\n  std::string filename_;\n\n  virtual std::tuple<double, double, double, double> GetCoordinateBounds()\n      const;\n};\n"
  },
  {
    "path": "src/libs/mazes/src/breadthfirstsearch.cpp",
    "content": "#include <mazes/breadthfirstsearch.h>\n#include <algorithm>\n#include <iostream>\n\nstd::vector<std::pair<int, int>> BreadthFirstSearch::SpanningTree(\n    int vertices, const Graph& adjacencylist) {\n  visited = std::vector<bool>(vertices, false);\n\n  int startvertex =\n      std::uniform_int_distribution<int>(0, vertices - 1)(generator);\n  currentlevel.push_back(startvertex);\n  visited[startvertex] = true;\n\n  spanningtree.clear();\n  while (!currentlevel.empty()) {\n    for (auto vertex : currentlevel) {\n      for (const auto& edge : adjacencylist[vertex]) {\n        int nextvertex = edge.first;\n        if (nextvertex < 0 or visited[nextvertex]) continue;\n        visited[nextvertex] = true;\n        spanningtree.push_back({vertex, nextvertex});\n        nextlevel.push_back(nextvertex);\n      }\n    }\n\n    currentlevel.clear();\n    swap(currentlevel, nextlevel);\n    shuffle(currentlevel.begin(), currentlevel.end(), generator);\n  }\n  return spanningtree;\n}\n"
  },
  {
    "path": "src/libs/mazes/src/cellborder.cpp",
    "content": "#include <mazes/cellborder.h>\n#include <cmath>\n#include <tuple>\n\nLineBorder::LineBorder(double x1, double y1, double x2, double y2)\n    : x1_(x1), y1_(y1), x2_(x2), y2_(y2) {}\n\nLineBorder::LineBorder(std::tuple<double, double, double, double> xy) {\n  std::tie(x1_, y1_, x2_, y2_) = xy;\n}\n\nstd::string LineBorder::GnuplotPrintString() const {\n  return \"set arrow from \" + std::to_string(x1_) + \",\" + std::to_string(y1_) +\n         \" to \" + std::to_string(x2_) + \",\" + std::to_string(y2_) +\n         \" nohead lt -1 lw 2\";\n}\n\nstd::string LineBorder::SVGPrintString() const {\n  return \"<line x1=\\\"\" + std::to_string(x1_ * 30) + \"\\\" x2=\\\"\" +\n         std::to_string(x2_ * 30) + \"\\\" y1=\\\"\" + std::to_string(y1_ * 30) +\n         \"\\\" y2=\\\"\" + std::to_string(y2_ * 30) +\n         \"\\\" stroke=\\\"black\\\" stroke-linecap=\\\"round\\\" stroke-width=\\\"3\\\"/>\";\n}\n\nArcBorder::ArcBorder(double cx, double cy, double r, double theta1,\n                     double theta2)\n    : cx_(cx), cy_(cy), r_(r), theta1_(theta1), theta2_(theta2) {}\n\nstd::string ArcBorder::GnuplotPrintString() const {\n  return \"set parametric; plot [\" + std::to_string(theta1_) + \":\" +\n         std::to_string(theta2_) + \"] \" + std::to_string(cx_) + \"+cos(t)*\" +\n         std::to_string(r_) + \",\" + std::to_string(cy_) + \"+sin(t)*\" +\n         std::to_string(r_) + \" w l lw 2 lt -1 notitle;unset parametric\";\n}\n\nstd::string ArcBorder::SVGPrintString() const {\n  double x1 = cx_ + r_ * cos(theta1_), y1 = cy_ + r_ * sin(theta1_);\n  double x2 = cx_ + r_ * cos(theta2_), y2 = cy_ + r_ * sin(theta2_);\n  return \"<path d=\\\"M \" + std::to_string(x2 * 30) + \" \" +\n         std::to_string(y2 * 30) + \" A \" + std::to_string(r_ * 30) + \" \" +\n         std::to_string(r_ * 30) + \", 0, 0, 0, \" + std::to_string(x1 * 30) +\n         \" \" + std::to_string(y1 * 30) +\n         \"\\\" stroke=\\\"black\\\" stroke-linecap=\\\"round\\\" stroke-width=\\\"3\\\" \"\n         \"fill=\\\"none\\\"/>\";\n}\n"
  },
  {
    "path": "src/libs/mazes/src/circularhexagonmaze.cpp",
    "content": "#include <mazes/circularhexagonmaze.h>\n#include <cmath>\n#include <iostream>\n\nCircularHexagonMaze::CircularHexagonMaze(int size) : HexagonalMaze(size) {}\n\nstd::shared_ptr<CellBorder> CircularHexagonMaze::GetEdge(int sector, int row,\n                                                         int column,\n                                                         int edge) const {\n  if (edge == 0) {\n    // Edge 0 is the bottom edge, hence connecting\n    // (row+1,column)-(row+1,column+1) with an arc\n    return std::make_shared<ArcBorder>(\n        0, 0, row + 1, (sector - 2) * M_PI / 3 + column * M_PI / 3 / (row + 1),\n        (sector - 2) * M_PI / 3 + (column + 1) * M_PI / 3 / (row + 1));\n  }\n\n  double ex1, ey1, ex2, ey2;\n  if (edge == 1) {\n    // (row,column)-(row+1,colum+1)\n    double theta1 = (sector - 2) * M_PI / 3, theta2 = (sector - 2) * M_PI / 3;\n    if (row > 0) theta1 += column * M_PI / 3 / row;\n    theta2 += (column + 1) * M_PI / 3 / (row + 1);\n\n    ex1 = row * cos(theta1);\n    ey1 = row * sin(theta1);\n    ex2 = (row + 1) * cos(theta2);\n    ey2 = (row + 1) * sin(theta2);\n  } else {\n    // (row,column)-(row+1,colum)\n    double theta1 = (sector - 2) * M_PI / 3, theta2 = (sector - 2) * M_PI / 3;\n    if (row > 0) theta1 += column * M_PI / 3 / row;\n    theta2 += column * M_PI / 3 / (row + 1);\n\n    ex1 = row * cos(theta1);\n    ey1 = row * sin(theta1);\n    ex2 = (row + 1) * cos(theta2);\n    ey2 = (row + 1) * sin(theta2);\n  }\n  return std::make_shared<LineBorder>(ex1, ey1, ex2, ey2);\n}\n\nstd::tuple<double, double, double, double>\nCircularHexagonMaze::GetCoordinateBounds() const {\n  return std::make_tuple(-size_, -size_, size_, size_);\n}\n"
  },
  {
    "path": "src/libs/mazes/src/circularmaze.cpp",
    "content": "#include <mazes/circularmaze.h>\n#include <cmath>\n#include <iostream>\n\nCircularMaze::CircularMaze(int size) : size_(size) {\n  ringnodecount_ = std::vector<int>(size_);\n  ringnodeprefixsum_ = std::vector<int>(size_);\n  ringnodecount_[0] = 1;\n  ringnodeprefixsum_[0] = 0;\n\n  for (int i = 1; i < size_; ++i) {\n    ringnodecount_[i] = ringnodecount_[i - 1];\n    if (2 * M_PI * i / ringnodecount_[i - 1] > 2) ringnodecount_[i] *= 2;\n    ringnodeprefixsum_[i] = ringnodeprefixsum_[i - 1] + ringnodecount_[i - 1];\n  }\n  vertices_ = ringnodecount_.back() + ringnodeprefixsum_.back();\n  startvertex_ = ringnodeprefixsum_.back();\n  endvertex_ = startvertex_ + ringnodecount_.back() / 2;\n}\n\nvoid CircularMaze::InitialiseGraph() {\n  Maze::InitialiseGraph();\n\n  for (int i = 1; i < size_; ++i) {\n    for (int j = 0; j < ringnodecount_[i]; ++j) {\n      int node = ringnodeprefixsum_[i] + j, nnode;\n      std::shared_ptr<CellBorder> ptr;\n\n      nnode = ringnodeprefixsum_[i - 1] +\n              (ringnodecount_[i - 1] * j) / ringnodecount_[i];\n      ptr = std::make_shared<ArcBorder>(\n          0, 0, i, j * 2 * M_PI / ringnodecount_[i] - M_PI / 2,\n          (j + 1) * 2 * M_PI / ringnodecount_[i] - M_PI / 2);\n      adjacencylist_[node].push_back({nnode, ptr});\n      adjacencylist_[nnode].push_back({node, ptr});\n\n      nnode = ringnodeprefixsum_[i] + ((j + 1) % ringnodecount_[i]);\n      double theta = (j + 1) * 2 * M_PI / ringnodecount_[i] - M_PI / 2;\n      ptr = std::make_shared<LineBorder>(i * cos(theta), i * sin(theta),\n                                         (i + 1) * cos(theta),\n                                         (i + 1) * sin(theta));\n      adjacencylist_[node].push_back({nnode, ptr});\n      adjacencylist_[nnode].push_back({node, ptr});\n\n      if (i == size_ - 1 and node != startvertex_ and node != endvertex_) {\n        ptr = std::make_shared<ArcBorder>(\n            0, 0, size_, j * 2 * M_PI / ringnodecount_[i] - M_PI / 2,\n            (j + 1) * 2 * M_PI / ringnodecount_[i] - M_PI / 2);\n        adjacencylist_[node].push_back({-1, ptr});\n      }\n    }\n  }\n}\n\nstd::tuple<double, double, double, double> CircularMaze::GetCoordinateBounds()\n    const {\n  return std::make_tuple(-size_, -size_, size_, size_);\n}\n"
  },
  {
    "path": "src/libs/mazes/src/depthfirstsearch.cpp",
    "content": "#include <mazes/depthfirstsearch.h>\n#include <algorithm>\n\nstd::vector<std::pair<int, int>> DepthFirstSearch::SpanningTree(\n    int vertices, const Graph& adjacencylist) {\n  spanningtree.clear();\n  visited = std::vector<bool>(vertices, 0);\n  DFS(std::uniform_int_distribution<int>(0, vertices - 1)(generator),\n      adjacencylist);\n  return spanningtree;\n}\n\nvoid DepthFirstSearch::DFS(int vertex, const Graph& adjacencylist) {\n  visited[vertex] = 1;\n  std::vector<int> nodeorder(adjacencylist[vertex].size());\n  std::iota(nodeorder.begin(), nodeorder.end(), 0);\n  shuffle(nodeorder.begin(), nodeorder.end(), generator);\n\n  for (auto index : nodeorder) {\n    int nextvertex = adjacencylist[vertex][index].first;\n    if (nextvertex < 0 or visited[nextvertex]) continue;\n    spanningtree.push_back({vertex, nextvertex});\n    DFS(nextvertex, adjacencylist);\n  }\n}\n"
  },
  {
    "path": "src/libs/mazes/src/hexagonalmaze.cpp",
    "content": "#include <mazes/hexagonalmaze.h>\n#include <cmath>\n#include <iostream>\n\nHexagonalMaze::HexagonalMaze(int size) : Maze(6 * size * size), size_(size) {\n  startvertex_ = VertexIndex(0, 1, size_ - 1, 0);\n  endvertex_ = VertexIndex(3, 1, size_ - 1, 0);\n}\n\nvoid HexagonalMaze::InitialiseGraph() {\n  Maze::InitialiseGraph();\n\n  // Hexagon can be split into 6 triangular sectors\n  // Each of which is subdivided into size_*size triangles\n\n  for (int sector = 0; sector < 6; ++sector) {\n    // Outer boundary, except entry and exit\n    for (int i = 0; i < size_; ++i) {\n      if ((i > 0) or (sector % 3 != 0)) {\n        std::shared_ptr<CellBorder> ptr =\n            this->GetEdge(sector, size_ - 1, i, 0);\n        adjacencylist_[VertexIndex(sector, 0, size_ - 1, i)].push_back(\n            {-1, ptr});\n      }\n    }\n\n    // Border between the 6 major triangles\n    for (int i = 0; i < size_; ++i) {\n      std::shared_ptr<CellBorder> ptr = this->GetEdge(sector, i, i, 1);\n      adjacencylist_[VertexIndex(sector, 0, i, i)].push_back(\n          {VertexIndex((sector + 1) % 6, 0, i, 0), ptr});\n      adjacencylist_[VertexIndex((sector + 1) % 6, 0, i, 0)].push_back(\n          {VertexIndex(sector, 0, i, i), ptr});\n    }\n\n    // 0-type edge\n    // Between up vertex (i,j) and down vertex (i,j)\n    for (int i = 0; i < size_ - 1; ++i) {\n      for (int j = 0; j <= i; ++j) {\n        std::shared_ptr<CellBorder> ptr = this->GetEdge(sector, i, j, 0);\n        adjacencylist_[VertexIndex(sector, 0, i, j)].push_back(\n            {VertexIndex(sector, 1, i, j), ptr});\n        adjacencylist_[VertexIndex(sector, 1, i, j)].push_back(\n            {VertexIndex(sector, 0, i, j), ptr});\n      }\n    }\n\n    // 1-type edge\n    // Between up vertex (i,j) and down vertex (i-1,j)\n    for (int i = 0; i < size_; ++i) {\n      for (int j = 0; j < i; ++j) {\n        std::shared_ptr<CellBorder> ptr = this->GetEdge(sector, i, j, 1);\n        adjacencylist_[VertexIndex(sector, 0, i, j)].push_back(\n            {VertexIndex(sector, 1, i - 1, j), ptr});\n        adjacencylist_[VertexIndex(sector, 1, i - 1, j)].push_back(\n            {VertexIndex(sector, 0, i, j), ptr});\n      }\n    }\n\n    // 2-type edge\n    // Between up vertex (i,j) and down vertex (i-1,j-1)\n    for (int i = 0; i < size_; ++i) {\n      for (int j = 1; j <= i; ++j) {\n        std::shared_ptr<CellBorder> ptr = this->GetEdge(sector, i, j, 2);\n        adjacencylist_[VertexIndex(sector, 0, i, j)].push_back(\n            {VertexIndex(sector, 1, i - 1, j - 1), ptr});\n        adjacencylist_[VertexIndex(sector, 1, i - 1, j - 1)].push_back(\n            {VertexIndex(sector, 0, i, j), ptr});\n      }\n    }\n  }\n}\n\nstd::shared_ptr<CellBorder> HexagonalMaze::GetEdge(int sector, int row,\n                                                   int column, int edge) const {\n  // Coordinates of vertices of 0th sector\n  double x1 = 0, y1 = 0, x2 = -size_ / 2.0, y2 = sqrt(3) * x2, x3 = -x2,\n         y3 = y2;\n  double dx12 = (x2 - x1) / size_, dy12 = (y2 - y1) / size_,\n         dx23 = (x3 - x2) / size_, dy23 = (y3 - y2) / size_;\n\n  double ex1, ey1, ex2, ey2;\n  if (edge == 0) {\n    // Edge 0 is the bottom edge, hence connecting\n    // (row+1,column)-(row+1,column+1)\n    ex1 = x1 + dx12 * (row + 1) + dx23 * column;\n    ey1 = y1 + dy12 * (row + 1) + dy23 * column;\n    ex2 = ex1 + dx23;\n    ey2 = ey1 + dy23;\n  } else if (edge == 1) {\n    // (row,column)-(row+1,colum+1)\n    ex1 = x1 + dx12 * row + dx23 * column;\n    ey1 = y1 + dy12 * row + dy23 * column;\n    ex2 = ex1 + dx12 + dx23;\n    ey2 = ey1 + dy12 + dy23;\n  } else {\n    // (row,column)-(row+1,colum)\n    ex1 = x1 + dx12 * row + dx23 * column;\n    ey1 = y1 + dy12 * row + dy23 * column;\n    ex2 = ex1 + dx12;\n    ey2 = ey1 + dy12;\n  }\n\n  // Finally rotate to actual sector\n  double theta = sector * M_PI / 3, sintheta = sin(theta),\n         costheta = cos(theta);\n  return std::make_shared<LineBorder>(\n      ex1 * costheta - ey1 * sintheta, ex1 * sintheta + ey1 * costheta,\n      ex2 * costheta - ey2 * sintheta, ex2 * sintheta + ey2 * costheta);\n}\n\nint HexagonalMaze::VertexIndex(int sector, int updown, int row,\n                               int column) const {\n  int vertexindex = sector * size_ * size_;\n  if (updown == 1) vertexindex += (size_ * (size_ + 1)) / 2;\n  vertexindex += (row * (row + 1)) / 2 + column;\n\n  return vertexindex;\n}\n\nstd::tuple<double, double, double, double> HexagonalMaze::GetCoordinateBounds()\n    const {\n  return std::make_tuple(-size_, -sqrt(3) / 2 * size_, size_,\n                         sqrt(3) / 2 * size_);\n}\n"
  },
  {
    "path": "src/libs/mazes/src/honeycombmaze.cpp",
    "content": "#include <mazes/honeycombmaze.h>\n#include <cmath>\n\nconst int HoneyCombMaze::neigh[6][2] = {{-1, 0}, {-1, 1}, {0, 1},\n                                        {1, 0},  {1, -1}, {0, -1}};\n\nHoneyCombMaze::HoneyCombMaze(int size)\n    : Maze(3 * size * (size - 1) + 1, 0, 3 * size * (size - 1)), size_(size) {}\n\nvoid HoneyCombMaze::InitialiseGraph() {\n  Maze::InitialiseGraph();\n\n  for (int u = -size_ + 1; u < size_; ++u) {\n    auto vextent = VExtent(u);\n    for (int v = vextent.first; v <= vextent.second; ++v) {\n      int node = VertexIndex(u, v);\n\n      cellCenters[node] = GetCenter(u, v);\n\n      for (int n = 0; n < 6; ++n) {\n        int uu = u + neigh[n][0], vv = v + neigh[n][1];\n        if (IsValidNode(uu, vv)) {\n          int nnode = VertexIndex(uu, vv);\n          if (nnode > node) continue;\n          std::shared_ptr<LineBorder> ptr =\n              std::make_shared<LineBorder>(GetEdge(u, v, n));\n          adjacencylist_[node].push_back({nnode, ptr});\n          adjacencylist_[nnode].push_back({node, ptr});\n        } else {\n            if (!bordersForEntranceAndExit)\n              if ((node == startvertex_ and n == 0) or\n                  (node == endvertex_ and n == 3))\n                continue;\n          adjacencylist_[node].push_back(\n              {-1, std::make_shared<LineBorder>(GetEdge(u, v, n))});\n        }\n      }\n    }\n  }\n}\n\n// u, v are diretions up and right-down\nint HoneyCombMaze::VertexIndex(int u, int v) const {\n  if (u <= 0)\n    return ((3 * size_ + u) * (size_ + u - 1)) / 2 + v;\n  else\n    return (3 * size_ * (size_ - 1) + (4 * size_ - u - 1) * u) / 2 + v;\n}\n\nstd::pair<double, double> HoneyCombMaze::GetCenter(int u, int v)\n{\n    double dxu = sqrt(3) / 2, dyu = 1.5, dxv = sqrt(3), dyv = 0;\n    double cx = dxu * u + dxv * v, cy = dyu * u + dyv * v;\n    return std::make_pair(cx, cy);\n}\n\nstd::tuple<double, double, double, double> HoneyCombMaze::GetEdge(\n    int u, int v, int edge) const {\n  double dxu = sqrt(3) / 2, dyu = 1.5, dxv = sqrt(3), dyv = 0;\n  double cx = dxu * u + dxv * v, cy = dyu * u + dyv * v;\n\n  double theta1 = (edge - 2.5) * M_PI / 3, theta2 = theta1 + M_PI / 3;\n  return std::make_tuple(cx + cos(theta1), cy + sin(theta1), cx + cos(theta2),\n                         cy + sin(theta2));\n}\n\nstd::tuple<double, double, double, double> HoneyCombMaze::GetCoordinateBounds()\n    const {\n  double xlim = sqrt(3) * (size_ - 0.5), ylim = 1.5 * size_ - 0.5;\n  return std::make_tuple(-xlim, -ylim, xlim, ylim);\n}\n\nstd::pair<int, int> HoneyCombMaze::VExtent(int u) {\n  if (u < 0)\n    return {-size_ - u + 1, size_ - 1};\n  else\n    return {-size_ + 1, size_ - 1 - u};\n}\n\nbool HoneyCombMaze::IsValidNode(int u, int v) {\n  if (u <= -size_ or u >= size_) return false;\n  auto vextent = VExtent(u);\n  return v >= vextent.first and v <= vextent.second;\n}\n"
  },
  {
    "path": "src/libs/mazes/src/kruskal.cpp",
    "content": "#include <mazes/kruskal.h>\n#include <algorithm>\n#include <numeric>\n#include <random>\n\nstd::vector<std::pair<int, int>> Kruskal::SpanningTree(\n    int vertices, const Graph& adjacencylist) {\n  std::vector<std::pair<int, int>> edges;\n  for (int i = 0; i < vertices; ++i) {\n    for (const auto& edge : adjacencylist[i]) {\n      if (edge.first > i) edges.push_back({i, edge.first});\n    }\n  }\n  shuffle(edges.begin(), edges.end(), generator);\n\n  parent_ = std::vector<int>(vertices);\n  std::iota(parent_.begin(), parent_.end(), 0);\n\n  spanningtree.clear();\n  for (const auto& edge : edges) {\n    int u = GetParent(edge.first), v = GetParent(edge.second);\n    if (u == v) continue;\n    parent_[u] = v;\n    spanningtree.push_back(edge);\n  }\n  return spanningtree;\n}\n\nint Kruskal::GetParent(int u) {\n  return (parent_[u] == u) ? u : (parent_[u] = GetParent(parent_[u]));\n}\n"
  },
  {
    "path": "src/libs/mazes/src/looperasedrandomwalk.cpp",
    "content": "#include <mazes/looperasedrandomwalk.h>\n#include <algorithm>\n\nstd::vector<std::pair<int, int>> LoopErasedRandomWalk::SpanningTree(\n    int vertices, const Graph& adjacencylist) {\n  spanningtree.clear();\n  visited = std::vector<int>(vertices, 0);\n\n  std::vector<int> nodes(vertices);\n  std::iota(nodes.begin(), nodes.end(), 0);\n  shuffle(nodes.begin(), nodes.end(), generator);\n  visited[nodes[0]] = 1;\n  for (int round = 1, i = 1; i < vertices; ++i) {\n    if (visited[nodes[i]]) continue;\n    ++round;\n    LERW(nodes[i], round, adjacencylist);\n  }\n\n  return spanningtree;\n}\n\nvoid LoopErasedRandomWalk::LERW(int vertex, int round,\n                                const Graph& adjacencylist) {\n  std::vector<int> current;\n\n  while (!visited[vertex]) {\n    visited[vertex] = round;\n    current.push_back(vertex);\n    int nextvertex;\n    do {\n      nextvertex =\n          adjacencylist[vertex]\n                       [std::uniform_int_distribution<int>(\n                            0, adjacencylist[vertex].size() - 1)(generator)]\n                           .first;\n    } while (nextvertex < 0);\n\n    if (visited[nextvertex] == round) {\n      // Erase the loop\n      do {\n        vertex = current.back();\n        visited[vertex] = 0;\n        current.pop_back();\n      } while (vertex != nextvertex);\n    }\n\n    vertex = nextvertex;\n  }\n  current.push_back(vertex);\n  for (unsigned int i = 0; i + 1 < current.size(); ++i) {\n    spanningtree.push_back({current[i], current[i + 1]});\n  }\n}\n"
  },
  {
    "path": "src/libs/mazes/src/maze.cpp",
    "content": "#include <mazes/maze.h>\n#include <algorithm>\n#include <fstream>\n#include <iostream>\n\nMaze::Maze(int vertices, int startvertex, int endvertex)\n    : vertices_(vertices), startvertex_(startvertex), endvertex_(endvertex) {}\n\nvoid Maze::InitialiseGraph() {\n  adjacencylist_.clear();\n  adjacencylist_.resize(vertices_);\n  cellCenters.resize(vertices_);\n}\n\nvoid Maze::GenerateMaze(SpanningtreeAlgorithm* algorithm) {\n  auto spanningtree = algorithm->SpanningTree(vertices_, adjacencylist_);\n  RemoveBorders(spanningtree);\n}\n\nvoid Maze::RemoveBorders(const std::vector<std::pair<int, int>>& edges) {\n  for (const auto& edge : edges) {\n    int u = edge.first, v = edge.second;\n    for (int i = 0; i < (int)adjacencylist_[u].size(); ++i) {\n      if (adjacencylist_[u][i].first == v) {\n        adjacencylist_[u].erase(adjacencylist_[u].begin() + i);\n        break;\n      }\n    }\n    for (int i = 0; i < (int)adjacencylist_[v].size(); ++i) {\n      if (adjacencylist_[v][i].first == u) {\n        adjacencylist_[v].erase(adjacencylist_[v].begin() + i);\n        break;\n      }\n    }\n  }\n}\n\nvoid Maze::PrintMazeGnuplot(const std::string& outputprefix) const {\n  std::ofstream gnuplotfile(outputprefix + \".plt\");\n  if (!gnuplotfile) {\n    std::cerr << \"Error opening \" << outputprefix << \".plt for writing.\\n\";\n    std::cerr << \"Terminating.\";\n    exit(1);\n  }\n\n  gnuplotfile << \"unset border\\n\";\n  gnuplotfile << \"unset tics\\n\";\n  gnuplotfile << \"set samples 15\\n\";\n  gnuplotfile << \"set lmargin at screen 0\\n\";\n  gnuplotfile << \"set rmargin at screen 1\\n\";\n  gnuplotfile << \"set bmargin at screen 0\\n\";\n  gnuplotfile << \"set tmargin at screen 1\\n\";\n\n  double xmin, ymin, xmax, ymax;\n  std::tie(xmin, ymin, xmax, ymax) = GetCoordinateBounds();\n  gnuplotfile << \"set xrange[\" << xmin - 1 << \":\" << xmax + 1 << \"]\\n\";\n  gnuplotfile << \"set yrange[\" << ymin - 1 << \":\" << ymax + 1 << \"]\\n\";\n\n  int xresolution = (xmax - xmin + 2) * 30,\n      yresolution = (ymax - ymin + 2) * 30;\n  gnuplotfile << \"set term pngcairo mono enhanced size \" << xresolution << \",\"\n              << yresolution << \"\\n\";\n\n  gnuplotfile << \"set output '\" << outputprefix << \".png'\\n\";\n  gnuplotfile << \"set multiplot\\n\";\n  for (int i = 0; i < vertices_; ++i) {\n    for (const auto& edge : adjacencylist_[i]) {\n      if (edge.first < i)\n        gnuplotfile << edge.second->GnuplotPrintString() << \"\\n\";\n    }\n  }\n  gnuplotfile << \"plot 1/0 notitle\\n\";\n  gnuplotfile << \"unset multiplot\\n\";\n  gnuplotfile << \"set output\\n\";\n}\n\nvoid Maze::PrintMazeSVG(const std::string& outputprefix) const {\n  std::ofstream svgfile(outputprefix + \".svg\");\n  if (!svgfile) {\n    std::cerr << \"Error opening \" << outputprefix << \".svg for writing.\\n\";\n    std::cerr << \"Terminating.\";\n    exit(1);\n  }\n  double xmin, ymin, xmax, ymax;\n  std::tie(xmin, ymin, xmax, ymax) = GetCoordinateBounds();\n  int xresolution = (xmax - xmin + 2) * 30,\n      yresolution = (ymax - ymin + 2) * 30;\n\n  svgfile << \"<svg width=\\\"\" << xresolution << \"\\\" height=\\\"\" << yresolution\n          << \"\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\" << std::endl;\n  svgfile << \"<g transform=\\\"translate(\" << (1 - xmin) * 30 << \",\"\n          << yresolution - (1 - ymin) * 30 << \") scale(1,-1)\\\">\" << std::endl;\n  svgfile << \"<rect x=\\\"\" << (xmin - 1) * 30 << \"\\\" y=\\\"\" << (ymin - 1) * 30\n          << \"\\\" width=\\\"\" << xresolution << \"\\\" height=\\\"\" << yresolution\n          << \"\\\" fill=\\\"white\\\"/>\" << std::endl;\n\n  for (int i = 0; i < vertices_; ++i) {\n    for (const auto& edge : adjacencylist_[i]) {\n      if (edge.first < i) {\n        svgfile << edge.second->SVGPrintString() << \"\\n\";\n      }\n    }\n  }\n  svgfile << \"</g>\" << std::endl;\n  svgfile << \"</svg>\" << std::endl;\n}\n"
  },
  {
    "path": "src/libs/mazes/src/prim.cpp",
    "content": "#include <mazes/prim.h>\n#include <algorithm>\n\nstd::vector<std::pair<int, int>> Prim::SpanningTree(\n    int vertices, const Graph& adjacencylist) {\n  spanningtree.clear();\n\n  PrimAlgorithm(vertices, adjacencylist);\n  return spanningtree;\n}\n\nvoid Prim::PrimAlgorithm(int vertices, const Graph& adjacencylist) {\n  std::vector<bool> visited(vertices, false);\n  std::vector<std::pair<int, int>> boundary;\n  int vertex = std::uniform_int_distribution<int>(0, vertices - 1)(generator);\n\n  for (int i = 1; i < vertices; ++i) {\n    visited[vertex] = true;\n    for (auto p : adjacencylist[vertex]) {\n      if (p.first != -1 and !visited[p.first])\n        boundary.push_back({vertex, p.first});\n    }\n\n    std::pair<int, int> nextedge = {-1, -1};\n    do {\n      int index =\n          std::uniform_int_distribution<int>(0, boundary.size() - 1)(generator);\n      std::swap(boundary[index], boundary.back());\n      if (!visited[boundary.back().second]) nextedge = boundary.back();\n      boundary.pop_back();\n    } while (nextedge.first == -1);\n\n    spanningtree.push_back(nextedge);\n    vertex = nextedge.second;\n  }\n}\n"
  },
  {
    "path": "src/libs/mazes/src/rectangularmaze.cpp",
    "content": "#include <mazes/rectangularmaze.h>\n\nRectangularMaze::RectangularMaze(int width, int height)\n    : Maze(width * height, 0, width * height - 1),\n      width_(width),\n      height_(height) {}\n\nint RectangularMaze::VertexIndex(int row, int column) {\n  return row * width_ + column;\n}\n\nvoid RectangularMaze::InitialiseGraph() {\n  Maze::InitialiseGraph();\n\n  // Lower and upper boundaries\n  for (int i = 0; i < width_; ++i) {\n    adjacencylist_[VertexIndex(0, i)].push_back(\n        {-1, std::make_shared<LineBorder>(i, 0, i + 1, 0)});\n    adjacencylist_[VertexIndex(height_ - 1, i)].push_back(\n        {-1, std::make_shared<LineBorder>(i, height_, i + 1, height_)});\n  }\n\n  // Left and right boundaries, leaving space for entry and exit\n  for (int i = 0; i < height_; ++i) {\n    if (i != 0)\n      adjacencylist_[VertexIndex(i, 0)].push_back(\n          {-1, std::make_shared<LineBorder>(0, i, 0, i + 1)});\n    if (i != height_ - 1)\n      adjacencylist_[VertexIndex(i, 0)].push_back(\n          {-1, std::make_shared<LineBorder>(width_, i, width_, i + 1)});\n  }\n\n  // Horizontally adjacent cells\n  for (int i = 0; i < height_; ++i) {\n    for (int j = 0; j < width_ - 1; ++j) {\n      std::shared_ptr<LineBorder> ptr =\n          std::make_shared<LineBorder>(j + 1, i, j + 1, i + 1);\n      adjacencylist_[VertexIndex(i, j)].push_back({VertexIndex(i, j + 1), ptr});\n      adjacencylist_[VertexIndex(i, j + 1)].push_back({VertexIndex(i, j), ptr});\n    }\n  }\n\n  // Vertically adjacent cells\n  for (int i = 0; i < height_ - 1; ++i) {\n    for (int j = 0; j < width_; ++j) {\n      std::shared_ptr<LineBorder> ptr =\n          std::make_shared<LineBorder>(j, i + 1, j + 1, i + 1);\n      adjacencylist_[VertexIndex(i, j)].push_back({VertexIndex(i + 1, j), ptr});\n      adjacencylist_[VertexIndex(i + 1, j)].push_back({VertexIndex(i, j), ptr});\n    }\n  }\n}\n\nstd::tuple<double, double, double, double>\nRectangularMaze::GetCoordinateBounds() const {\n  return std::make_tuple(0, 0, width_, height_);\n}\n"
  },
  {
    "path": "src/libs/mazes/src/spanningtreealgorithm.cpp",
    "content": "#include <mazes/spanningtreealgorithm.h>\n\nSpanningtreeAlgorithm::SpanningtreeAlgorithm() {\n  generator = std::mt19937(randomdevice());\n}\n"
  },
  {
    "path": "src/libs/mazes/src/usermaze.cpp",
    "content": "#include <mazes/usermaze.h>\n#include <fstream>\n\nUserMaze::UserMaze(std::string filename) : filename_(filename) {}\n\nvoid UserMaze::InitialiseGraph() {\n  Maze::InitialiseGraph();\n\n  std::ifstream in(filename_);\n  in >> vertices_;\n  startvertex_ = 0;\n  endvertex_ = vertices_ - 1;\n\n  adjacencylist_.clear();\n  adjacencylist_.resize(vertices_);\n\n  xmin_ = std::numeric_limits<double>::max(), ymin_ = xmin_;\n  xmax_ = std::numeric_limits<double>::min(), ymax_ = xmax_;\n  int i, j;\n  while (in >> i >> j) {\n    std::string bordertype;\n    in >> bordertype;\n    if (bordertype == \"Line\") {\n      double x1, x2, y1, y2;\n      in >> x1 >> y1 >> x2 >> y2;\n      xmax_ = std::max(xmax_, x2);\n      ymax_ = std::max(ymax_, y2);\n      xmin_ = std::min(xmin_, x1);\n      ymin_ = std::min(ymin_, y1);\n      adjacencylist_[i].push_back(\n          {j, std::make_shared<LineBorder>(x1, y1, x2, y2)});\n    } else if (bordertype == \"Arc\") {\n      double cx, cy, r, theta1, theta2;\n      in >> cx >> cy >> r >> theta1 >> theta2;\n      xmax_ = std::max(xmax_, cx + r);\n      ymax_ = std::max(ymax_, cy + r);\n      xmin_ = std::min(xmin_, cx - r);\n      ymin_ = std::min(ymin_, cy - r);\n      adjacencylist_[i].push_back(\n          {j, std::make_shared<ArcBorder>(cx, cy, r, theta1, theta2)});\n    } else\n      continue;\n    if (j != -1)\n      adjacencylist_[j].push_back({i, adjacencylist_[i].back().second});\n  }\n}\n\nstd::tuple<double, double, double, double> UserMaze::GetCoordinateBounds()\n    const {\n  return std::make_tuple(xmin_, ymin_, xmax_, ymax_);\n}\n"
  },
  {
    "path": "src/libs/rendering/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(librendering VERSION 0.1 LANGUAGES CXX)\n\nadd_library_default(rendering)\ntarget_link_libraries(rendering PUBLIC env Magnum::MeshTools Magnum::Primitives)\n"
  },
  {
    "path": "src/libs/rendering/include/rendering/render_utils.hpp",
    "content": "#pragma once\n\n#include <map>\n#include <tuple>\n\n#include <env/env.hpp>\n\n#include <Magnum/Trade/MeshData.h>\n\n\nnamespace Megaverse\n{\n\nvoid initPrimitives(std::map<DrawableType, Magnum::Trade::MeshData> &meshData);\n\nclass Overview\n{\npublic:\n    void saveTransformation()\n    {\n        rootTransformation = root->transformation();\n        verticalTiltTransformation = verticalTilt->transformation();\n    }\n\n    void restoreTransformation() const\n    {\n        root->setTransformation(rootTransformation);\n        verticalTilt->setTransformation(verticalTiltTransformation);\n    }\n\n    void reset(Object3D *parent);\n\npublic:\n    Object3D *root{}, *verticalTilt{};\n\n    Magnum::SceneGraph::Camera3D *camera{};\n    bool enabled = false;\n\n    float verticalRotation = 0.0f;\n\n    Magnum::Matrix4 rootTransformation{}, verticalTiltTransformation{};\n};\n\n}"
  },
  {
    "path": "src/libs/rendering/src/render_utils.cpp",
    "content": "#include <Magnum/Primitives/Cube.h>\n#include <Magnum/Primitives/Cone.h>\n#include <Magnum/Primitives/Capsule.h>\n#include <Magnum/Primitives/Cylinder.h>\n#include <Magnum/Primitives/Icosphere.h>\n\n#include <Magnum/GL/Framebuffer.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n\n#include <Magnum/SceneGraph/Camera.h>\n\n#include <env/env_renderer.hpp>\n\n#include <rendering/render_utils.hpp>\n\nusing namespace Megaverse;\n\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\n\nvoid Megaverse::initPrimitives(std::map<DrawableType, Magnum::Trade::MeshData> &meshes)\n{\n    auto &m = meshes;  // type less\n\n    m.emplace(DrawableType::Box, Primitives::cubeSolid());\n    m.emplace(DrawableType::Capsule, Primitives::capsule3DSolid(3, 3, 8, 1.0));\n    m.emplace(DrawableType::Sphere, Primitives::icosphereSolid(1));\n    m.emplace(DrawableType::Cone, Primitives::coneSolid(1, 6, 0.5f));\n    m.emplace(DrawableType::Cylinder, Primitives::cylinderSolid(1, 6, 0.5f, Magnum::Primitives::CylinderFlag::CapEnds));\n}\n\n\nvoid Overview::reset(Object3D *parent)\n{\n    root = &parent->addChild<Object3D>();\n    root->rotateYLocal(225.0_degf);\n    root->translateLocal(Magnum::Vector3{0.1f, 20.0f, 0.1f});\n\n    verticalTilt = &root->addChild<Object3D>();\n    verticalTilt->rotateXLocal(-40.0_degf);\n    verticalRotation = -40.0f;\n\n    camera = &(verticalTilt->addFeature<SceneGraph::Camera3D>());\n\n    auto [fov, near, far, aspectRatio] = overviewCameraParameters();\n    camera->setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend)\n           .setProjectionMatrix(Matrix4::perspectiveProjection(Deg(fov), aspectRatio, near, far))\n           .setViewport(GL::defaultFramebuffer.viewport().size());\n\n    if (rootTransformation != Matrix4{} || verticalTiltTransformation != Matrix4{})\n        restoreTransformation();\n    else\n        saveTransformation();\n}\n"
  },
  {
    "path": "src/libs/scenarios/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(libscenarios VERSION 0.1 LANGUAGES CXX)\n\nadd_library_default(scenarios)\ntarget_link_libraries(scenarios PUBLIC env util mazes)\n"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/component_fall_detection.hpp",
    "content": "#pragma once\n\n#include <env/scenario_component.hpp>\n\n\nnamespace Megaverse\n{\n\nclass FallDetectionCallbacks\n{\npublic:\n    virtual ~FallDetectionCallbacks() = default;\n    virtual void agentFell(int /*agentIdx*/) {}\n};\n\ntemplate<typename VoxelT>\nclass FallDetectionComponent : public ScenarioComponent\n{\npublic:\n    explicit FallDetectionComponent(Scenario &scenario, VoxelGrid<VoxelT> &grid, FallDetectionCallbacks &callbacks, int fallThreshold = -20)\n    : ScenarioComponent{scenario}\n    , grid{grid}\n    , callbacks{callbacks}\n    , fallThreshold{fallThreshold}\n    {\n    }\n\n    void reset(Env &, Env::EnvState &) override\n    {\n        agentInitialPositions.clear();\n    }\n\n    void step(Env &env, Env::EnvState &envState) override\n    {\n        for (int i = 0; i < env.getNumAgents(); ++i) {\n            auto &a = envState.agents[i];\n            if (a->absoluteTransformation().translation().y() < fallThreshold) {\n                resetAgent(i, a);\n                callbacks.agentFell(i);\n            }\n        }\n    }\n\n    void resetAgent(int agentIdx, AbstractAgent *a)\n    {\n        auto p = agentInitialPositions[agentIdx];\n        auto v = grid.getWithVector(p);\n        while (v && !v->empty() && p.y() < 1000) {\n            ++p.y();\n            v = grid.getWithVector(p);\n        }\n\n        const float halfVoxel = grid.getVoxelSize() / 2;\n        a->teleport(btVector3{p.x() + halfVoxel, p.y() + halfVoxel, p.z() + halfVoxel});\n    }\n\npublic:\n    VoxelGrid<VoxelT> &grid;\n    std::vector<Magnum::Vector3> agentInitialPositions;\n    FallDetectionCallbacks &callbacks;\n    int fallThreshold = -20;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/component_hexagonal_maze.hpp",
    "content": "#pragma once\n\n\n#include <env/scenario_component.hpp>\n\n\nclass HoneyCombMaze;\n\nnamespace Megaverse\n{\n\nclass HexagonalMazeComponent : public ScenarioComponent\n{\npublic:\n    explicit HexagonalMazeComponent(Scenario &scenario);\n\n    ~HexagonalMazeComponent() override;\n\n    void reset(Env &, Env::EnvState &) override;\n\n    void addDrawablesAndCollisions(DrawablesMap &drawables, Env::EnvState &envState) const;\n\n    HoneyCombMaze & getMaze() const { return *maze; }\n\n    [[nodiscard]] float getScale() const { return mazeScale; }\n    [[nodiscard]] int getSize() const { return mazeSize; }\n\npublic:\n    int minSize = 2, maxSize = 10;\n    float omitWallsProbabilityMin = 0.1f, omitWallsProbabilityMax = 0.7f;\n\nprivate:\n    int mazeSize = 0;\n    float mazeScale = 1.0f;\n    float wallHeight = 1.0f;\n    float omitWallsProbability = 0.0f;\n    ColorRgb bottomEdgingColor, topEdgingColor;\n    float wallLandmarkProbability = 0.0f;\n\n    std::unique_ptr<HoneyCombMaze> maze;\n    double xMin = 0, xMax = 0, yMin = 0, yMax = 0;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/component_object_stacking.hpp",
    "content": "#pragma once\n\n\n#include <env/scenario_component.hpp>\n\n\nnamespace Megaverse\n{\n\nstruct VoxelWithPhysicsObjects : public VoxelState\n{\n    RigidBody *physicsObject = nullptr;\n};\n\nclass ObjectStackingCallbacks\n{\npublic:\n    virtual ~ObjectStackingCallbacks() = default;\n    virtual bool canPlaceObject(int /*agentIdx*/, const VoxelCoords &, Object3D * /*obj*/) { return true; }\n    virtual void placedObject(int /*agentIdx*/, const VoxelCoords &, Object3D * /*obj*/) {}\n    virtual void pickedObject(int /*agentIdx*/, const VoxelCoords &, Object3D * /*obj*/) {}\n};\n\n/**\n * @tparam VoxelT has to have the field \"physicsObject\"\n * SFINAE check or C++20 concepts check would be nice here.\n */\ntemplate<typename VoxelT>\nclass ObjectStackingComponent : public ScenarioComponent\n{\npublic:\n    explicit ObjectStackingComponent(Scenario &scenario, int numAgents, VoxelGrid<VoxelT> &grid, ObjectStackingCallbacks &callbacks)\n    : ScenarioComponent{scenario}\n    , grid{grid}\n    , carryingObject(size_t(numAgents), nullptr)\n    , callbacks{callbacks}\n    {\n    }\n\n    void reset(Env &, Env::EnvState &) override\n    {\n        std::fill(carryingObject.begin(), carryingObject.end(), nullptr);\n    }\n\n    void step(Env &env, Env::EnvState &envState) override\n    {\n        for (int i = 0; i < env.getNumAgents(); ++i) {\n            const auto a = envState.currAction[i];\n            if (!!(a & Action::Interact))\n                onInteractAction(i, envState);\n        }\n    }\n\n    Object3D * agentCarryingObject(int agentIdx) const\n    {\n        return carryingObject[agentIdx];\n    }\n\n    void onInteractAction(int agentIdx, Env::EnvState &envState)\n    {\n        AbstractAgent *agent = envState.agents[agentIdx];\n\n        const auto carryingScale = 0.78f, carryingScaleInverse = 1.0f / carryingScale;\n\n        // putting object on the ground\n        if (carryingObject[agentIdx]) {\n            auto obj = carryingObject[agentIdx];\n            const auto t = obj->absoluteTransformation().translation();\n\n            VoxelCoords voxel = grid.getCoords(t);\n            auto voxelPtr = grid.get(voxel);\n\n            bool collidesWithAgent = false;\n\n            for (const auto a : envState.agents) {\n                if (a == agent)\n                    continue;\n\n                const auto agentTransformation = a->transformation().translation();\n                VoxelCoords c = grid.getCoords(agentTransformation);\n\n                if (voxel == c) {\n                    collidesWithAgent = true;\n                    break;\n                }\n            }\n\n            const bool empty = !voxelPtr || (voxelPtr->empty() && !voxelPtr->physicsObject);\n            if (empty && !collidesWithAgent && callbacks.canPlaceObject(agentIdx, voxel, obj)) {\n                // voxel in front of us is empty, can place the object\n                // the object should be on the ground or on top of another object\n                // descend on y axis until we find ground\n\n                while (true) {\n                    VoxelCoords voxelBelow{voxel.x(), voxel.y() - 1, voxel.z()};\n                    if (voxelBelow.y() < -30) {\n                        // this is the lowest level we support\n                        break;\n                    }\n\n                    auto voxelBelowPtr = grid.get(voxelBelow);\n                    if (voxelBelowPtr && (voxelBelowPtr->solid() || voxelBelowPtr->physicsObject))\n                        break;\n                    else\n                        voxel = voxelBelow;\n                }\n\n                // placing object on the ground (or another object)\n                if (!grid.hasVoxel(voxel)) {\n                    VoxelT voxelState;\n                    grid.set(voxel, voxelState);\n                }\n\n                grid.get(voxel)->physicsObject = obj;\n\n                obj->setParent(envState.scene.get());\n\n                auto scaling = obj->transformation().scaling();\n                obj->resetTransformation();\n                obj->scale({scaling.x() * carryingScaleInverse, scaling.y() * carryingScaleInverse, scaling.z() * carryingScaleInverse});\n                obj->translate({float(voxel.x()) + 0.5f, float(voxel.y()) + 0.5f, float(voxel.z()) + 0.5f});\n                obj->syncPose();\n\n                obj->toggleCollision();\n\n                carryingObject[agentIdx] = nullptr;\n\n                callbacks.placedObject(agentIdx, voxel, obj);\n            }\n\n        } else {\n            // picking up an object\n            const auto pickup = agent->interactLocation()->absoluteTransformation().translation();\n            VoxelCoords voxel = lround(floor(pickup));\n            VoxelCoords voxelAbove{voxel.x(), voxel.y() + 1, voxel.z()};\n\n            int pickupHeight = 0, maxPickupHeight = 1;\n            while (pickupHeight <= maxPickupHeight) {\n                auto voxelPtr = grid.get(voxel), voxelAbovePtr = grid.get(voxelAbove);\n                bool hasObjectAbove = voxelAbovePtr && voxelAbovePtr->physicsObject;\n\n                if (voxelPtr && voxelPtr->physicsObject && !hasObjectAbove) {\n                    auto obj = voxelPtr->physicsObject;\n                    obj->toggleCollision();\n\n                    obj->setParent(agent);\n                    auto scaling = obj->transformation().scaling();\n                    obj->resetTransformation();\n\n                    obj->scale({scaling.x() * carryingScale, scaling.y() * carryingScale, scaling.z() * carryingScale});\n                    obj->translate({0.0f, -0.3f, 0.0f});\n                    obj->setParent(agent->interactLocation());\n\n                    carryingObject[agentIdx] = obj;\n                    voxelPtr->physicsObject = nullptr;\n                    callbacks.pickedObject(agentIdx, voxel, obj);\n\n                    break;\n\n                } else {\n                    voxel = voxelAbove;\n                    voxelAbove = VoxelCoords{voxel.x(), voxel.y() + 1, voxel.z()};\n                }\n\n                ++pickupHeight;\n            }\n        }\n    }\n\n    void addDrawablesAndCollisions(DrawablesMap &drawables, Env::EnvState &envState, const std::vector<VoxelCoords> &objectPositions)\n    {\n        const auto objSize = 0.39f;\n        auto objScale = Magnum::Vector3{objSize, objSize, objSize};\n\n        for (const auto &movableObject : objectPositions) {\n            const auto pos = movableObject;\n            auto translation = Magnum::Vector3{float(pos.x()) + 0.5f, float(pos.y()) + 0.5f, float(pos.z()) + 0.5f};\n\n            auto bBoxShape = std::make_unique<btBoxShape>(btVector3{1, 1, 1});\n\n            auto &object = envState.scene->addChild<RigidBody>(envState.scene.get(), 0.0f, bBoxShape.get(), envState.physics->bWorld);\n            object.scale(objScale).translate(translation);\n            object.setCollisionScale({1.15f, 1.15f, 1.15f});\n            object.setCollisionOffset({0, -0.05f, 0});\n            object.syncPose();\n\n            drawables[DrawableType::Box].emplace_back(&object, rgb(ColorRgb::MOVABLE_BOX));\n\n            envState.physics->collisionShapes.emplace_back(std::move(bBoxShape));\n\n            if (!grid.hasVoxel(pos)) {\n                VoxelT voxelState;\n                grid.set(pos, voxelState);\n            }\n\n            grid.get(pos)->physicsObject = &object;\n        }\n    }\n\nprivate:\n    VoxelGrid<VoxelT> &grid;\n\n    std::vector<RigidBody *> carryingObject;\n\n    ObjectStackingCallbacks &callbacks;\n};\n\n}\n"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/component_platforms.hpp",
    "content": "#pragma once\n\n#include <env/scenario_component.hpp>\n\n#include <scenarios/platforms.hpp>\n\n\n\nnamespace Megaverse\n{\n\nclass PlatformsComponent : public ScenarioComponent\n{\npublic:\n    explicit PlatformsComponent(Scenario &scenario)\n        : ScenarioComponent{scenario}\n    {\n    }\n\n    void reset(Env &, Env::EnvState &) override\n    {\n        platforms.clear();\n        levelRoot.reset();\n        levelRoot = std::make_unique<Object3D>(nullptr);\n    }\n\n    void addPlatform(std::unique_ptr<Platform> platform)\n    {\n        platforms.emplace_back(std::move(platform));\n    }\n\npublic:\n    std::vector<std::unique_ptr<Platform>> platforms;\n    std::unique_ptr<Object3D> levelRoot;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/component_voxel_grid.hpp",
    "content": "#pragma once\n\n#include <unordered_set>\n\n#include <util/voxel_grid.hpp>\n\n#include <env/scenario_component.hpp>\n\n#include <scenarios/platforms.hpp>\n\n\nnamespace Megaverse\n{\n\nstruct CoordRange\n{\n    int min, max;\n};\n\ninline CoordRange startEndCoord(int bboxMin, int bboxMax, int direction)\n{\n    if (direction == 1)\n        return {bboxMax + 1, bboxMax + 1};\n    else if (direction == -1)\n        return {bboxMin - 1, bboxMin - 1};\n    else\n        return {bboxMin, bboxMax};\n}\n\nusing Boxes = std::vector<BoundingBox>;\n\n\nstruct BBoxInfo\n{\npublic:\n    BBoxInfo() = default;\n    BBoxInfo(uint8_t type, ColorRgb color)\n    : type{type}\n    , color{color}\n    {}\n\n    bool operator <(const BBoxInfo &info) const\n    {\n        return type == info.type ? color < info.color : type < info.type;\n    }\n\npublic:\n    uint8_t type{};\n    ColorRgb color{};\n};\n\n\n// comment this to disable voxel layout optimization, i.e. for ablation study\n#define OPTIMIZE_VOXEL_LAYOUT\n\n\n/**\n * Environments that use voxel grids for layouts or runtime checks should include this component.\n * @tparam VoxelT data stored in each non-empty voxel cell.\n */\ntemplate<typename VoxelT>\nclass VoxelGridComponent : public ScenarioComponent\n{\npublic:\n    explicit VoxelGridComponent(Scenario &scenario, int maxVoxelsXYZ = 100, float minX = 0, float minY = 0, float minZ = 0, float voxelSize = 1)\n    : ScenarioComponent{scenario}\n    , grid{size_t(maxVoxelsXYZ), {minX, minY, minZ}, voxelSize}\n    {\n    }\n\n    void reset(Env &, Env::EnvState &) override { grid.clear(); }\n\n    void addPlatform(const Platform &p, ColorRgb layoutColor, ColorRgb wallColor, bool drawWalls = true)\n    {\n        for (auto &bb : p.layoutBoxes)\n            addBoundingBox(bb.boundingBox(), VoxelState::generateType(true, true), TERRAIN_NONE, layoutColor);\n        for (auto &bb : p.wallBoxes)\n            addBoundingBox(bb.boundingBox(), VoxelState::generateType(true, drawWalls), TERRAIN_NONE, wallColor);\n\n        for (auto &[terrainType, v] : p.terrainBoxes)\n            for (auto &bb : v)\n                addTerrainBoundingBox(bb.boundingBox(), terrainType);\n    }\n\n    template<typename... Args>\n    void addBoundingBox(const BoundingBox &bb, Args&&... args)\n    {\n        for (int x = bb.min.x(); x < bb.max.x(); ++x)\n            for (int y = bb.min.y(); y < bb.max.y(); ++y)\n                for (int z = bb.min.z(); z < bb.max.z(); ++z)\n                    grid.set({x, y, z}, makeVoxel<VoxelT>(std::forward<Args>(args)...));\n    }\n\n    template<typename... Args>\n    void addTerrainBoundingBox(const BoundingBox &bb, int terrain)\n    {\n        for (int x = bb.min.x(); x < bb.max.x(); ++x)\n            for (int y = bb.min.y(); y < bb.max.y(); ++y)\n                for (int z = bb.min.z(); z < bb.max.z(); ++z) {\n                    const VoxelCoords coords{x, y, z};\n                    if (!grid.hasVoxel(coords))\n                        grid.set({x, y, z}, VoxelT());\n\n                    grid.get(coords)->terrain |= terrain;\n                }\n    }\n\n    std::map<BBoxInfo, Boxes> toBoundingBoxes()\n    {\n        const static Magnum::Vector3i directions[] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};\n\n        std::unordered_set<VoxelCoords> visited;\n\n        const auto gridHashMap = grid.getHashMap();\n\n        std::map<BBoxInfo, Boxes> boxesByVoxelType;\n\n        for (auto it : gridHashMap) {\n            const auto &coord = it.first;\n            const auto &voxel = it.second;\n            const auto voxelType = voxel.voxelType;\n            const auto color = voxel.color;\n\n            if (visited.count(coord)) {\n                // already processed this voxel\n                continue;\n            }\n\n            visited.emplace(coord);\n\n            BoundingBox bbox{coord, coord};\n            std::vector<VoxelCoords> expansion;\n\n#ifdef OPTIMIZE_VOXEL_LAYOUT\n            // try to expand the parallelepiped in every direction as far as we can\n            for (auto direction : directions) {\n                for (int sign = -1; sign <= 1; sign += 2) {\n                    auto d = direction * sign;\n\n                    bool canExpand = true;\n\n                    // expanding in a specific direction as far as we can\n                    while (true) {\n                        const auto xlim = startEndCoord(bbox.min.x(), bbox.max.x(), d.x());\n                        const auto ylim = startEndCoord(bbox.min.y(), bbox.max.y(), d.y());\n                        const auto zlim = startEndCoord(bbox.min.z(), bbox.max.z(), d.z());\n\n                        expansion.clear();\n\n                        for (auto x = xlim.min; x <= xlim.max; ++x)\n                            for (auto y = ylim.min; y <= ylim.max; ++y)\n                                for (auto z = zlim.min; z <= zlim.max; ++z) {\n                                    const VoxelCoords coords{x, y, z};\n                                    const auto v = grid.get(coords);\n                                    if (!v || v->voxelType != voxelType || v->color != color || visited.count(coords)) {\n                                        // we could not expand in this direction\n                                        canExpand = false;\n                                        goto afterLoop;\n                                    }\n\n                                    expansion.emplace_back(coords);\n                                }\n\n                        afterLoop:\n\n                        if (!canExpand)\n                            break;\n\n                        for (auto newVoxelCoord : expansion) {\n                            visited.emplace(newVoxelCoord);\n                            bbox.addPoint(newVoxelCoord);\n                        }\n                    }\n                }\n            }\n#else\n            UNUSED(directions);\n#endif\n\n            // finished expanding in all possible directions\n            // the bounding box defines the parallepiped completely filled by solid voxels\n            // we can draw only this parallelepiped (8 vertices) instead of drawing individual voxels, saving a ton of time\n            boxesByVoxelType[{voxelType, color}].emplace_back(bbox);\n        }\n\n        return boxesByVoxelType;\n    }\n\npublic:\n    VoxelGrid<VoxelT> grid;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/const.hpp",
    "content": "#pragma once\n\n#include <env/const.hpp>\n\n\nnamespace Megaverse::Str\n{\n    ConstStr obstaclesMinNumPlatforms = \"obstaclesMinNumPlatforms\",\n             obstaclesMaxNumPlatforms = \"obstaclesMaxNumPlatforms\",\n             obstaclesMinGap = \"obstaclesMinGap\",\n             obstaclesMaxGap = \"obstaclesMaxGap\",\n             obstaclesMinLava = \"obstaclesMinLava\",\n             obstaclesMaxLava = \"obstaclesMaxLava\",\n             obstaclesMinHeight = \"obstaclesMinHeight\",\n             obstaclesMaxHeight = \"obstaclesMaxHeight\",\n             obstaclesAgentAtExit = \"obstaclesAgentAtExit\",\n             obstaclesAllAgentsAtExit = \"obstaclesAllAgentsAtExit\",\n             obstaclesExtraReward = \"obstaclesExtraReward\",\n             obstaclesNumAllowedMaxDifficulty = \"obstaclesNumAllowedMaxDifficulty\",\n             obstaclesAgentCarriedObjectToExit = \"obstaclesAgentCarriedObjectToExit\";\n\n    ConstStr towerPickedUpObject = \"towerPickedUpObject\",\n             towerVisitedBuildingZoneWithObject = \"towerVisitedBuildingZoneWithObject\",\n             towerBuildingReward = \"towerBuildingReward\";\n\n    ConstStr collectSingleGood = \"collectSingleGood\",\n             collectSingleBad = \"collectSingleBad\",\n             collectAll = \"collectAll\",\n             collectAbyss = \"collectAbyss\";\n\n    ConstStr sokobanBoxOnTarget = \"sokobanBoxOnTarget\",\n             sokobanBoxLeavesTarget = \"sokobanBoxLeavesTarget\",\n             sokobanAllBoxesOnTarget = \"sokobanAllBoxesOnTarget\";\n\n    ConstStr boxagoneTouchedFloor = \"boxagoneTouchedFloor\",\n             boxagonePerStepReward = \"boxagonePerStepReward\";\n\n    ConstStr exploreSolved = \"exploreSolved\";\n\n    ConstStr memoryCollectGood = \"memoryCollectGood\",\n             memoryCollectBad = \"memoryCollectBad\";\n\n    ConstStr rearrangeOneMoreObjectCorrectPosition = \"rearrangeOneMoreObjectCorrectPosition\",\n             rearrangeAllObjectsCorrectPosition = \"rearrangeAllObjectsCorrectPosition\";\n}\n"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/init.hpp",
    "content": "#pragma once\n\n#include <env/scenario.hpp>\n\n#include <scenarios/scenario_empty.hpp>\n#include <scenarios/scenario_sokoban.hpp>\n#include <scenarios/scenario_collect.hpp>\n#include <scenarios/scenario_football.hpp>\n#include <scenarios/scenario_obstacles.hpp>\n#include <scenarios/scenario_rearrange.hpp>\n#include <scenarios/scenario_hex_memory.hpp>\n#include <scenarios/scenario_box_a_gone.hpp>\n#include <scenarios/scenario_hex_explore.hpp>\n#include <scenarios/scenario_tower_building.hpp>\n\n\nnamespace Megaverse\n{\n\ntemplate <typename ScenarioType>\nvoid registerScenario(const std::string &name)\n{\n    Scenario::registerScenario(name, Scenario::scenarioFactory<ScenarioType>);\n}\n\nvoid scenariosGlobalInit()\n{\n    static bool initialized = false;\n    if (initialized)\n        return;\n    initialized = true;\n\n    // used for debugging and testing\n    registerScenario<EmptyScenario>(\"Empty\");\n    registerScenario<TestScenario>(\"Test\");\n\n    // experimental\n    registerScenario<FootballScenario>(\"Football\");\n    registerScenario<BoxAGoneScenario>(\"BoxAGone\");\n\n    // \"main\" envs\n    registerScenario<TowerBuildingScenario>(\"TowerBuilding\");\n    registerScenario<ObstaclesEasyScenario>(\"ObstaclesEasy\");\n    registerScenario<ObstaclesHardScenario>(\"ObstaclesHard\");\n    registerScenario<CollectScenario>(\"Collect\");\n    registerScenario<SokobanScenario>(\"Sokoban\");\n    registerScenario<HexMemoryScenario>(\"HexMemory\");\n    registerScenario<HexExploreScenario>(\"HexExplore\");\n    registerScenario<RearrangeScenario>(\"Rearrange\");\n\n    registerScenario<ObstaclesMediumScenario>(\"ObstaclesMedium\");\n\n    // auxiliary obstacle scenarios, for \"curriculum\"\n    registerScenario<ObstaclesOnlyWallsScenario>(\"ObstaclesWalls\");\n    registerScenario<ObstaclesOnlyStepsScenario>(\"ObstaclesSteps\");\n    registerScenario<ObstaclesOnlyLavaScenario>(\"ObstaclesLava\");\n}\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/layout_utils.hpp",
    "content": "#pragma once\n\n#include <util/voxel_grid.hpp>\n\n#include <env/env.hpp>\n\n#include <scenarios/component_voxel_grid.hpp>\n\n\nnamespace Megaverse\n{\n    template<typename VoxelT>\n    void addDrawablesAndCollisionObjectsFromVoxelGrid(VoxelGridComponent<VoxelT> &vg, DrawablesMap &drawables, Env::EnvState &envState, float voxelSize)\n    {\n        auto boundingBoxesByType = vg.toBoundingBoxes();\n        for (auto &[bbInfo, bb] : boundingBoxesByType)\n            addBoundingBoxes(drawables, envState, bb, bbInfo.type, bbInfo.color, voxelSize);\n    }\n\n    void addBoundingBoxes(DrawablesMap &drawables, Env::EnvState &envState, const Boxes &boxes, int voxelType, ColorRgb color, float voxelSize);\n    void addTerrain(DrawablesMap &drawables, Env::EnvState &envState, TerrainType type, const BoundingBox &bb, float voxelSize = 1.0f);\n\n    void addStaticCollidingBox(\n        DrawablesMap &drawables, Env::EnvState &envState,\n        Magnum::Vector3 scale, Magnum::Vector3 translation, ColorRgb color\n    );\n\n    Object3D * addCylinder(DrawablesMap &drawables, Object3D &parent, Magnum::Vector3 translation, Magnum::Vector3 scale, ColorRgb color);\n    Object3D * addSphere(DrawablesMap &drawables, Object3D &parent, Magnum::Vector3 translation, Magnum::Vector3 scale, ColorRgb color);\n    Object3D * addPillar(DrawablesMap &drawables, Object3D &parent, Magnum::Vector3 translation, Magnum::Vector3 scale, ColorRgb color);\n    Object3D * addDiamond(DrawablesMap &drawables, Object3D &parent, Magnum::Vector3 translation, Magnum::Vector3 scale, ColorRgb color);\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/platforms.hpp",
    "content": "#pragma once\n\n#include <set>\n#include <map>\n#include <cassert>\n\n#include <util/util.hpp>\n#include <util/magnum.hpp>\n#include <util/voxel_grid.hpp>\n#include <util/math_utils.hpp>\n#include <util/tiny_logger.hpp>\n\n#include <env/env.hpp>\n\n#include <scenarios/const.hpp>\n\n\nnamespace Megaverse\n{\n\nenum PlatformOrientation\n{\n    ORIENTATION_STRAIGHT,\n    ORIENTATION_TURN_LEFT,\n    ORIENTATION_TURN_RIGHT,\n};\n\nenum TerrainType\n{\n    TERRAIN_NONE = 0,\n    TERRAIN_EXIT = 1,\n    TERRAIN_LAVA = 1 << 1,\n    TERRAIN_BUILDING_ZONE = 1 << 2,\n};\n\nenum {\n    WALLS_SOUTH = 1,\n    WALLS_NORTH = 1 << 1,\n    WALLS_WEST = 1 << 2,\n    WALLS_EAST = 1 << 3,\n\n    WALLS_NONE = 0,\n    WALLS_ALL = WALLS_SOUTH | WALLS_NORTH | WALLS_EAST | WALLS_WEST,\n};\n\n\ninline ColorRgb terrainColor(TerrainType type)\n{\n    const static std::map<TerrainType, ColorRgb> colors = {\n        {TerrainType::TERRAIN_EXIT, ColorRgb::EXIT_PAD},\n        {TerrainType::TERRAIN_LAVA, ColorRgb::RED},\n        {TerrainType::TERRAIN_BUILDING_ZONE, ColorRgb::BUILDING_ZONE},\n    };\n\n    return colors.at(type);\n}\n\n\nstruct BoundingBox\n{\n    BoundingBox() = default;\n\n    BoundingBox(const VoxelCoords &min, const VoxelCoords &max)\n        : min{min}, max{max}\n    {\n    }\n\n    BoundingBox(int minX, int minY, int minZ, int maxX, int maxY, int maxZ)\n        : min{minX, minY, minZ}\n        , max{maxX, maxY, maxZ}\n    {\n    }\n\n    void addPoint(const VoxelCoords &v)\n    {\n        if (v.x() < min.x()) min.x() = v.x();\n        if (v.x() > max.x()) max.x() = v.x();\n\n        if (v.y() < min.y()) min.y() = v.y();\n        if (v.y() > max.y()) max.y() = v.y();\n\n        if (v.z() < min.z()) min.z() = v.z();\n        if (v.z() > max.z()) max.z() = v.z();\n    }\n\n    void sort()\n    {\n        // sort the min/max vertices after the transformation\n        // this only works for rotations in 90-degree increments\n        if (min.x() > max.x()) std::swap(min.x(), max.x());\n        if (min.y() > max.y()) std::swap(min.y(), max.y());\n        if (min.z() > max.z()) std::swap(min.z(), max.z());\n    }\n\n    [[nodiscard]] bool collidesWith(const BoundingBox &other) const\n    {\n        // we're looking for an axis with no overlap\n        if (max.x() <= other.min.x()) return false;\n        if (min.x() >= other.max.x()) return false;\n        if (max.y() <= other.min.y()) return false;\n        if (min.y() >= other.max.y()) return false;\n        if (max.z() <= other.min.z()) return false;\n        if (min.z() >= other.max.z()) return false;\n\n        return true;\n    }\n\npublic:\n    VoxelCoords min, max;\n};\n\n\nstruct MagnumAABB\n{\n    MagnumAABB(Object3D &parent, const BoundingBox &bb)\n    : min(&parent.addChild<Object3D>())\n    , max(&parent.addChild<Object3D>())\n    {\n        min->translateLocal(Magnum::Vector3(bb.min));\n        max->translateLocal(Magnum::Vector3(bb.max));\n    }\n\n    [[nodiscard]] BoundingBox boundingBox() const\n    {\n        BoundingBox bb;\n        bb.min = Magnum::Math::lround(min->absoluteTransformation().translation());\n        bb.max = Magnum::Math::lround(max->absoluteTransformation().translation());\n        bb.sort();\n        return bb;\n    }\n\npublic:\n    Object3D *min, *max;\n};\n\n\nclass Platform\n{\npublic:\n    explicit Platform(Object3D *parent, Rng &rng, int walls, const FloatParams &params)\n    : rng{rng}\n    , walls{walls}\n    , root{&parent->addChild<Object3D>()}\n    , params{params}\n    {\n    }\n    virtual ~Platform() = default;\n\n    virtual void init() = 0;\n\n    virtual void generate() = 0;\n\n    virtual void rotateCCW(int /*previousPlatformWidth*/)\n    {\n        root->rotateYLocal(degrees(90.0));\n        root->translateLocal({-1, 0, -1});\n    }\n\n    virtual void rotateCW(int previousPlatformWidth)\n    {\n        root->rotateYLocal(degrees(-90.0));\n        root->translateLocal({float(previousPlatformWidth) - 1, 0, -float(width) + 1});\n    }\n\n    virtual Object3D * anchorPoint() { return nextPlatformAnchor; }\n\n    virtual void addFloor()\n    {\n        MagnumAABB floor{*root, {0, 0, 0, length, 1, width}};\n        layoutBoxes.emplace_back(floor);\n\n        nextPlatformAnchor = &root->addChild<Object3D>();\n        nextPlatformAnchor->translateLocal({float(length), 0, 0});\n\n        boundingBoxDirty = true;\n    }\n\n    virtual void addWalls()\n    {\n        if (walls & WALLS_SOUTH)\n            wallBoxes.emplace_back(MagnumAABB{*root, {0, 0, 0, 1, height, width}});\n        if (walls & WALLS_NORTH)\n            wallBoxes.emplace_back(MagnumAABB{*root, {length - 1, 0, 0, length, height, width}});\n        if (walls & WALLS_EAST)\n            wallBoxes.emplace_back(MagnumAABB{*root, {0, 0, 0, length, height, 1}});\n        if (walls & WALLS_WEST)\n            wallBoxes.emplace_back(MagnumAABB{*root, {0, 0, width - 1, length, height, width}});\n\n        boundingBoxDirty = true;\n    }\n\n    virtual BoundingBox platformBoundingBox()\n    {\n        if (!boundingBoxDirty)\n            return outerBoundingBox;\n\n        if (!layoutBoxes.empty())\n            outerBoundingBox = layoutBoxes.front().boundingBox();\n        else if (!wallBoxes.empty())\n            outerBoundingBox = wallBoxes.front().boundingBox();\n        else\n            outerBoundingBox = BoundingBox{};\n\n        boundingBoxDirty = false;\n\n        for (auto &boxes : {layoutBoxes, wallBoxes})\n            for (auto &box : boxes) {\n                const auto bb = box.boundingBox();\n                outerBoundingBox.addPoint(bb.min);\n                outerBoundingBox.addPoint(bb.max);\n            }\n\n        return outerBoundingBox;\n    }\n\n    virtual bool collidesWith(Platform &other)\n    {\n        return platformBoundingBox().collidesWith(other.platformBoundingBox());\n    }\n\n    virtual std::vector<Magnum::Vector3> agentSpawnPoints(int numAgents)\n    {\n        std::vector<Magnum::Vector3> spawnPoints;\n        std::set<std::pair<int, int>> used;\n\n        for (int i = 0; i < numAgents; ++i) {\n            int x, y, z;\n\n            for (int attempt = 0; attempt < 10; ++attempt) {\n                x = randRange(1, length - 1, rng);\n                z = randRange(1, width - 1, rng);\n                if (used.count({x, z}))\n                    continue;\n\n                y = occupancy[{x, z}] + 1;\n                occupancy[{x, z}] += 2;\n                spawnPoints.emplace_back(x, y, z);\n                used.emplace(x, z);\n                break;\n            }\n        }\n\n        return spawnPoints;\n    }\n\n    virtual int requiresMovableBoxesToTraverse() { return 0; }\n\n    virtual std::vector<VoxelCoords> generateObjectPositions(int numPositionsToGenerate)\n    {\n        std::vector<VoxelCoords> boxes;\n        constexpr int maxAttempts = 10;\n\n        for (int i = 0; i < numPositionsToGenerate; ++i) {\n            for (int attempt = 0; attempt < 10; ++attempt) {\n                const int x = randRange(1, length - 1, rng);\n                const int z = randRange(1, width - 1, rng);\n                if (occupancy[{x, z}] < 2 || attempt >= maxAttempts - 1) {\n                    const int y = ++occupancy[{x, z}];\n                    boxes.emplace_back(x, y, z);\n                    break;\n                }\n            }\n        }\n\n        return adjustTransformation(boxes);\n    }\n\n    std::vector<VoxelCoords> adjustTransformation(std::vector<VoxelCoords> &coords) const\n    {\n        for (auto &c : coords) {\n            Magnum::Vector3 v{c.x() + 0.5f, c.y() + 0.5f, c.z() + 0.5f};\n            c = toVoxel(root->absoluteTransformation().transformPoint(v));\n        }\n\n        return coords;\n    }\n\n    int param(const std::string &str) const\n    {\n        return int(lround(params.at(str)));\n    }\n\n    virtual bool isMaxDifficulty() const { return false; }\n\npublic:\n    Rng &rng;\n\n    int walls{};\n\n    // length = x, height = y, width = z\n    int length{}, height{}, width{};\n\n    std::vector<MagnumAABB> layoutBoxes, wallBoxes;\n    std::map<TerrainType, std::vector<MagnumAABB>> terrainBoxes;\n\n    Object3D *nextPlatformAnchor{}, *root{};\n\n    bool boundingBoxDirty = true;\n    BoundingBox outerBoundingBox;\n\n    std::map<std::pair<int, int>, int> occupancy;\n\n    const FloatParams &params;\n};\n\nclass EmptyPlatform : public Platform\n{\npublic:\n    explicit EmptyPlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int w = -1)\n        : Platform{parent, rng, walls, params}\n    {\n        width = w;\n    }\n\n    void init() override\n    {\n        length = randRange(4, 10, rng);\n        if (width == -1)\n            width = randRange(5, 9, rng);\n\n        // height = randRange(3, 7, rng);\n        height = 5;\n    }\n\n    void generate() override\n    {\n        addFloor();\n        addWalls();\n    }\n};\n\nclass WallPlatform : public EmptyPlatform\n{\npublic:\n    explicit WallPlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int w = -1)\n        : EmptyPlatform{parent, rng, walls, params, w}\n    {\n    }\n\n    void init() override\n    {\n        EmptyPlatform::init();\n\n        wallHeight = randRange(param(Str::obstaclesMinHeight), param(Str::obstaclesMaxHeight) + 1, rng);\n        height = randRange(wallHeight + 4, wallHeight + 6, rng);\n    }\n\n    void generate() override\n    {\n        EmptyPlatform::generate();\n\n        const auto wallX = randRange(1, length, rng);\n        const auto wallThickness = randRange(1, length - wallX + 1, rng);\n\n        MagnumAABB wall{*root, {wallX, 1, 1, wallX + wallThickness, 1 + wallHeight, width - 1}};\n        layoutBoxes.emplace_back(wall);\n\n        // this way we won't generate boxes on top of the wall (for the most part)\n        for (int x = wallX; x < wallX + wallThickness; ++x)\n            for (int z = 1; z < width; ++z)\n                occupancy[{x, z}] = wallHeight;\n    }\n\n    int requiresMovableBoxesToTraverse() override { return triangularNumber(wallHeight - 1); }\n\n    bool isMaxDifficulty() const override\n    {\n        return wallHeight >= param(Str::obstaclesMaxHeight);\n    }\n\nprivate:\n    int wallHeight{};\n};\n\nclass LavaPlatform : public EmptyPlatform\n{\npublic:\n    explicit LavaPlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int w = -1)\n        : EmptyPlatform{parent, rng, walls, params, w}\n    {\n    }\n\n    void init() override\n    {\n        EmptyPlatform::init();\n        length = randRange(6, 12, rng);\n        auto minLava = std::min(param(Str::obstaclesMinLava), length - 2);\n        auto maxLava = std::min(param(Str::obstaclesMaxLava) + 1, length - 1);\n        lavaLength = randRange(minLava, maxLava, rng);\n    }\n\n    void generate() override\n    {\n        EmptyPlatform::generate();\n\n        const auto lavaX = randRange(1, length - lavaLength, rng);\n\n        MagnumAABB lava{*root, {lavaX, 1, 1, lavaX + lavaLength, 2, width - 1}};\n        terrainBoxes[TERRAIN_LAVA].emplace_back(lava);\n    }\n\n    int requiresMovableBoxesToTraverse() override { return std::max(1, lavaLength - 1); }\n\n    bool isMaxDifficulty() const override { return lavaLength >= param(Str::obstaclesMaxLava); }\n\nprivate:\n    int lavaLength{};\n};\n\nclass StepPlatform : public EmptyPlatform\n{\npublic:\n    explicit StepPlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int w = -1)\n        : EmptyPlatform{parent, rng, walls, params, w}\n    {\n    }\n\n    void init() override\n    {\n        EmptyPlatform::init();\n\n        stepHeight = randRange(param(Str::obstaclesMinHeight), param(Str::obstaclesMaxHeight) + 1, rng);\n        height = randRange(stepHeight + 2, stepHeight + 5, rng);\n    }\n\n    void generate() override\n    {\n        const auto stepX = randRange(1, length, rng);\n        MagnumAABB floorLow{*root, {0, 0, 0, stepX + 1, 1, width}};\n        MagnumAABB floorHigh{*root, {stepX, stepHeight, 0, length, stepHeight + 1, width}};\n        MagnumAABB wall{*root, {stepX, 0, 0, stepX + 1, stepHeight + 1, width}};\n\n        layoutBoxes.emplace_back(floorLow);\n        layoutBoxes.emplace_back(floorHigh);\n        layoutBoxes.emplace_back(wall);\n\n        nextPlatformAnchor = &root->addChild<Object3D>();\n        nextPlatformAnchor->translateLocal({float(length), float(stepHeight), 0});\n\n        addWalls();\n\n        // this way we won't generate boxes on top of the step (for the most part)\n        for (int x = stepX + 1; x < length; ++x)\n            for (int z = 1; z < width; ++z)\n                occupancy[{x, z}] = stepHeight;\n    }\n\n    int requiresMovableBoxesToTraverse() override { return triangularNumber(stepHeight - 1); }\n\n    bool isMaxDifficulty() const override\n    {\n        return stepHeight >= param(Str::obstaclesMaxHeight);\n    }\n\nprivate:\n    int stepHeight{};\n};\n\n\nclass GapPlatform : public EmptyPlatform\n{\npublic:\n    explicit GapPlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int w = -1)\n        : EmptyPlatform{parent, rng, walls, params, w}\n    {\n    }\n\n    void init() override\n    {\n        EmptyPlatform::init();\n\n        gap = randRange(param(Str::obstaclesMinGap), std::min(param(Str::obstaclesMaxGap) + 1, length - 1), rng);\n        gapX = randRange(1, length - gap, rng);\n    }\n\n    void generate() override\n    {\n        MagnumAABB floorStart{*root, {0, 0, 0, gapX, 1, width}};\n        MagnumAABB floorEnd{*root, {gapX + gap, 0, 0, length, 1, width}};\n\n        layoutBoxes.emplace_back(floorStart);\n        layoutBoxes.emplace_back(floorEnd);\n\n        nextPlatformAnchor = &root->addChild<Object3D>();\n        nextPlatformAnchor->translateLocal({float(length), 0, 0});\n\n        addWalls();\n    }\n\n    int requiresMovableBoxesToTraverse() override { return triangularNumber(std::max(0, gap - 2)); }\n\n    std::vector<VoxelCoords> generateObjectPositions(int numPositionsToGenerate) override\n    {\n        std::vector<VoxelCoords> boxes, candidates;\n\n        for (int x = 0; x < length; ++x)\n            for (int z = 1; z < width - 1; ++z) {\n                if (x >= gapX && x < gapX + gap)\n                    continue;\n                candidates.emplace_back(x, 1, z);\n            }\n\n        for (int i = 0; i < numPositionsToGenerate; ++i) {\n            const auto v = randomSample(candidates, rng);\n            const int y = ++occupancy[{v.x(), v.z()}];\n            boxes.emplace_back(v.x(), y, v.z());\n        }\n\n        return adjustTransformation(boxes);\n    }\n\nprivate:\n    int gap{}, gapX{};\n};\n\nclass StartPlatform : public EmptyPlatform\n{\npublic:\n    explicit StartPlatform(Object3D *parent, Rng &rng, const FloatParams &params, int w = -1)\n        : EmptyPlatform{parent, rng, WALLS_SOUTH | WALLS_EAST | WALLS_WEST, params, w}\n    {\n    }\n\n    void init() override\n    {\n        EmptyPlatform::init();\n    }\n};\n\nclass ExitPlatform : public EmptyPlatform\n{\npublic:\n    explicit ExitPlatform(Object3D *parent, Rng &rng, const FloatParams &params, int w = -1)\n        : EmptyPlatform{parent, rng, WALLS_NORTH | WALLS_EAST | WALLS_WEST, params, w}\n    {\n    }\n\n    void generate() override\n    {\n        EmptyPlatform::generate();\n\n        MagnumAABB exit{*root, {length - 3, 1, 1, length - 1, 3, width - 1}};\n        terrainBoxes[TERRAIN_EXIT].emplace_back(exit);\n    }\n};\n\nclass TransitionPlatform : public EmptyPlatform\n{\npublic:\n    explicit TransitionPlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int l, int w)\n        : EmptyPlatform{parent, rng, walls, params, -1}\n    {\n        length = l, width = w;\n    }\n\n    void init() override { height = 5; }\n};\n\n}\n"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_box_a_gone.hpp",
    "content": "#pragma once\n\n#include <deque>\n\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/component_platforms.hpp>\n#include <scenarios/component_voxel_grid.hpp>\n#include <scenarios/component_fall_detection.hpp>\n\n\nnamespace Megaverse\n{\n\nstruct VoxelBoxAGone : public VoxelState\n{\n    RigidBody *disappearingPlatform = nullptr;\n} __attribute__((aligned(8)));\n\nclass BoxAGoneScenario : public DefaultScenario, public FallDetectionCallbacks\n{\nprivate:\n    class BoxAGonePlatform;\n\n    struct AgentState\n    {\n        RigidBody *lastPlatform = nullptr;\n        float secondsBeforeTouchedFloor = 0.0f;\n    };\n\n    struct PlatformState\n    {\n        int remainingTicks = 0;\n        VoxelCoords coords;\n        RigidBody *temporaryPlatform = nullptr;\n    } __attribute__((aligned(32)));\n\npublic:\n    explicit BoxAGoneScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~BoxAGoneScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override;\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    void addDisappearingPlatforms(DrawablesMap &drawables);\n\n    /**\n     * Different trueObjective depending on whether this is a single-agent or competitive setting.\n     */\n    float trueObjective(int agentIdx) const override\n    {\n        if (env.getNumAgents() > 1) {\n            // last man standing wins\n            float maxSecondsBeforeTouchingFloor = 0.0f;\n            int bestAgent = 0;\n            for (int i = 0; i < env.getNumAgents(); ++i)\n                if (agentStates[i].secondsBeforeTouchedFloor > maxSecondsBeforeTouchingFloor)\n                    bestAgent = i, maxSecondsBeforeTouchingFloor = agentStates[i].secondsBeforeTouchedFloor;\n\n            return agentIdx == bestAgent;  // winner gets 1, other agents get 0\n        } else {\n            // fraction of the episode for which we managed to avoid the floor\n            return agentStates[agentIdx].secondsBeforeTouchedFloor / episodeLengthSec();\n        }\n    }\n\n    void initializeDefaultParameters() override\n    {\n        auto &fp = floatParams;\n        fp[Str::episodeLengthSec] = 300.0f;\n        fp[Str::verticalLookLimitRad] = 0.75f;\n    }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        return {\n            {Str::boxagoneTouchedFloor,  -0.1f},\n            {Str::boxagonePerStepReward, 0.01f},\n        };\n    }\n\n    /**\n     * Each agent is for himself.\n     */\n    int teamAffinity(int agentIdx) const override { return agentIdx; }\n\nprivate:\n    constexpr static float voxelSize = 2.0f;\n    constexpr static int platformSize = 24;\n\n    bool finished = false;\n\n    VoxelGridComponent<VoxelBoxAGone> vg;\n    PlatformsComponent platformsComponent;\n\n    FallDetectionComponent<VoxelBoxAGone> fallDetection;\n\n    std::unique_ptr<BoxAGonePlatform> platform;\n\n    std::vector<std::pair<VoxelCoords, ColorRgb>> disappearingPlatforms;\n    std::vector<VoxelCoords> spawnPositions;\n\n    std::vector<AgentState> agentStates;\n    std::map<RigidBody *, PlatformState> platformStates;\n    std::deque<RigidBody *> extraPlatforms;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_collect.hpp",
    "content": "#pragma once\n\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/component_voxel_grid.hpp>\n#include <scenarios/component_fall_detection.hpp>\n#include <scenarios/component_object_stacking.hpp>\n\n\nnamespace Megaverse\n{\n\nstruct VoxelCollect : public VoxelWithPhysicsObjects\n{\n    Object3D *rewardObject = nullptr;\n    int reward = 0;\n};\n\n\nclass CollectScenario : public DefaultScenario, public ObjectStackingCallbacks, public FallDetectionCallbacks\n{\npublic:\n    explicit CollectScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~CollectScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void createLandscape();\n\n    void step() override;\n\n    void agentFell(int agentIdx) override;\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    float trueObjective(int /*agentIdx*/) const override { return solved; }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        return {\n            {Str::collectSingleGood, 1.0f},\n            {Str::collectSingleBad, -1.0f},\n            {Str::collectAll, 5.0f},\n            {Str::collectAbyss, -0.5f},\n        };\n    }\n\n    float episodeLengthSec() const override\n    {\n        // add a little bit of time for every extra reward object\n        return Scenario::episodeLengthSec() + 2.0f * rewardPositions.size();\n    }\n\nprivate:\n    bool solved = false;\n\n    VoxelGridComponent<VoxelCollect> vg;\n    ObjectStackingComponent<VoxelCollect> objectStackingComponent;\n    FallDetectionComponent<VoxelCollect> fallDetection;\n\n    std::vector<VoxelCoords> objectPositions, rewardPositions;\n    std::vector<Magnum::Vector3> agentPositions;\n\n    int numPositiveRewards = 0, positiveRewardsCollected = 0;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_default.hpp",
    "content": "#pragma once\n\n#include <util/magnum.hpp>\n\n#include <env/scenario.hpp>\n\n\nnamespace Megaverse\n{\n\n/**\n * Default base class for scenarios containing some boilerplate code.\n * Allows us to avoid code duplication for the most standard things.\n * Scenarios don't have to inherit from DefaultScenario, they are free to inherit directly from scenario to retain\n * full flexibility.\n */\nclass DefaultScenario : public Scenario\n{\npublic:\n    struct UIElement\n    {\n    public:\n        UIElement() = default;\n\n        UIElement(Object3D *anchor, Object3D *uiElement)\n        : anchor{anchor}\n        , uiElement{uiElement}\n        {\n        }\n\n        void rescale(const Magnum::Vector3 &requiredScale) const\n        {\n            const auto scale = uiElement->transformation().scaling();\n            uiElement->scaleLocal(requiredScale / scale);\n        }\n\n        void show()\n        {\n            if (visible)\n                return;\n\n            anchor->translate({-1000, 0, 0});\n            visible = true;\n        }\n\n        void hide()\n        {\n            if (!visible)\n                return;\n\n            anchor->translate({1000, 0, 0});\n            visible = false;\n        }\n\n    public:\n        bool visible = true;\n        Object3D *anchor = nullptr;\n        Object3D *uiElement = nullptr;\n    };\n\n    struct DefaultUI\n    {\n        std::vector<UIElement> remainingTimeBars, positiveRewardIndicator, negativeRewardIndicator;\n        float initialRemainingTimeBarScale = 0.24f;\n    };\n\npublic:\n    explicit DefaultScenario(const std::string &scenarioName, Env &env, Env::EnvState &envState)\n    : Scenario{scenarioName, env, envState}\n    {\n        const auto numAgents = env.getNumAgents();\n        defaultUI.remainingTimeBars.resize(numAgents);\n        defaultUI.positiveRewardIndicator.resize(numAgents), defaultUI.negativeRewardIndicator.resize(numAgents);\n    }\n\n    /**\n     * Override this if your scenario needs agents of a different type or a different logic for spawning agents.\n     * @param agents resulting vector of agents\n     */\n    void spawnAgents(std::vector<AbstractAgent *> &agents) override\n    {\n        const auto numAgents = env.getNumAgents();\n        const auto verticalLookLimitRad = floatParams[Str::verticalLookLimitRad];\n        const auto agentPositions = agentStartingPositions();\n\n        for (int i = 0; i < numAgents; ++i) {\n            auto randomRotation = frand(envState.rng) * Magnum::Constants::pi() * 2;\n            auto &agent = envState.scene->addChild<DefaultKinematicAgent>(\n                envState.scene.get(), envState.physics->bWorld,\n                Magnum::Vector3{agentPositions[i]} + Magnum::Vector3{0.5, 0.0, 0.5},\n                randomRotation, verticalLookLimitRad\n            );\n            agent.updateTransform();\n\n            agents.emplace_back(&agent);\n        }\n    }\n\n    void addEpisodeAgentsDrawables(DrawablesMap &drawables) override\n    {\n        const auto numAgents = env.getNumAgents();\n\n        // drawing agent's body in single-agent envs is still useful because of the overview camera\n#ifdef DONT_DRAW_SELF\n        if (numAgents <= 1) {\n            // agent can't see itself, so we can avoid wasting resources on rendering it\n            return;\n        }\n#endif\n\n        for (int i = 0; i < numAgents; ++i) {\n            auto agent = envState.agents[i];\n\n            auto &agentBody = agent->addChild<Object3D>();\n            agentBody.scale({0.35f, 0.36f, 0.35f}).translate({0, 0.09f, 0});\n\n            drawables[DrawableType::Capsule].emplace_back(&agentBody, rgb(agentColors[i % numAgentColors]));\n\n            auto &eyesObject = agent->getCameraObject()->addChild<Object3D>();\n            eyesObject.scale({0.25f, 0.12f, 0.2f}).translate({0.0f, 0.0f, -0.19f});\n\n            drawables[DrawableType::Box].emplace_back(&eyesObject, rgb(ColorRgb::AGENT_EYES));\n\n            // visualize location where agent interacts with objects\n            // auto &pickupSpot = agent.pickupSpot->addChild<Object3D>();\n            // pickupSpot.scale({0.03f, 0.03f, 0.03f});\n            // addStandardDrawable(DrawableType::Box, pickupSpot, 0x222222_rgbf);\n        }\n    }\n\n    void addUIDrawables(DrawablesMap &drawables) override\n    {\n        const auto numAgents = env.getNumAgents();\n        for (int i = 0; i < numAgents; ++i) {\n            auto agent = envState.agents[i];\n\n            auto &uiObject = agent->getCameraObject()->addChild<Object3D>();\n            uiObject.translate({0, 0, -0.2f});\n\n            auto &remainingTimeBarAnchor = uiObject.addChild<Object3D>();\n            remainingTimeBarAnchor.translate({0, -0.131f, 0});\n            auto &remainingTimeBar = remainingTimeBarAnchor.addChild<Object3D>();\n            remainingTimeBar.scaleLocal({defaultUI.initialRemainingTimeBarScale, 0.0015, 0.001});\n            drawables[DrawableType::Box].emplace_back(&remainingTimeBar, rgb(ColorRgb::BLUE));\n            defaultUI.remainingTimeBars[i] = UIElement{&remainingTimeBarAnchor, &remainingTimeBar};\n\n            if (floatParams[Str::useUIRewardIndicators] > 0) {\n                auto addRewardIndicator = [&](float xOffset, ColorRgb color, std::vector<UIElement> &container) {\n                    auto &indicatorAnchor = uiObject.addChild<Object3D>();\n                    indicatorAnchor.translate({xOffset, 0, 0});\n                    auto &indicator = indicatorAnchor.addChild<Object3D>();\n                    indicator.scaleLocal({0.01, 0.03, 0.0001});\n                    drawables[DrawableType::Box].emplace_back(&indicator, rgb(color));\n                    container[i] = UIElement{&indicatorAnchor, &indicator};\n                    container[i].hide();\n                };\n\n                addRewardIndicator(-0.23f, ColorRgb::GREEN, defaultUI.positiveRewardIndicator);\n                addRewardIndicator(0.23f, ColorRgb::RED, defaultUI.negativeRewardIndicator);\n            }\n        }\n    }\n\n    void updateUI() override\n    {\n        const auto numAgents = env.getNumAgents();\n        for (int i = 0; i < numAgents; ++i) {\n            auto &bar = defaultUI.remainingTimeBars[i];\n            bar.rescale({env.remainingTimeFraction() * defaultUI.initialRemainingTimeBarScale, 0.0015, 0.001});\n\n            if (floatParams[Str::useUIRewardIndicators] > 0) {\n                if (envState.lastReward[i] > FLT_EPSILON) {\n                    defaultUI.positiveRewardIndicator[i].show();\n                    defaultUI.positiveRewardIndicator[i].rescale({0.06, 0.04f * envState.lastReward[i], 0.0001});\n                    defaultUI.negativeRewardIndicator[i].hide();\n                } else if (envState.lastReward[i] < -FLT_EPSILON) {\n                    defaultUI.negativeRewardIndicator[i].show();\n                    defaultUI.negativeRewardIndicator[i].rescale({0.06, -0.04f * envState.lastReward[i], 0.0001});\n                    defaultUI.positiveRewardIndicator[i].hide();\n                } else {\n                    defaultUI.positiveRewardIndicator[i].hide();\n                    defaultUI.negativeRewardIndicator[i].hide();\n                }\n            }\n        }\n    }\n\n    std::vector<Magnum::Color3> getPalette() const override\n    {\n        std::vector<Magnum::Color3> palette;\n        for (auto c : allColors)\n            palette.emplace_back(rgb(c));\n\n        return palette;\n    }\n\nprotected:\n    DefaultUI defaultUI;\n};\n\n}\n"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_empty.hpp",
    "content": "#pragma once\n\n#include <scenarios/scenario_default.hpp>\n\n\nnamespace Megaverse\n{\n\nclass EmptyScenario : public DefaultScenario\n{\npublic:\n    explicit EmptyScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~EmptyScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override {}\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    float trueObjective(int) const override { return 0; }\n\n    RewardShaping defaultRewardShaping() const override { return {}; }\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_football.hpp",
    "content": "#pragma once\n\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/component_platforms.hpp>\n#include <scenarios/component_voxel_grid.hpp>\n#include <scenarios/layout_utils.hpp>\n\n\nnamespace Megaverse\n{\n\nclass FootballScenario : public DefaultScenario\n{\nprivate:\n    class FootballLayout;\n\npublic:\n    explicit FootballScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~FootballScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override;\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    float trueObjective(int) const override { return 0; }//TODO\n\n    RewardShaping defaultRewardShaping() const override { return {}; }\n\nprivate:\n    VoxelGridComponent<VoxelState> vg;\n    PlatformsComponent platformsComponent;\n\n    std::unique_ptr<btSphereShape> collisionShape;\n    Object3D *footballObject = nullptr;\n\n    std::unique_ptr<FootballLayout> layout;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_hex_explore.hpp",
    "content": "#pragma once\n\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/component_hexagonal_maze.hpp>\n\nnamespace Megaverse\n{\n\nclass HexExploreScenario : public DefaultScenario\n{\npublic:\n    explicit HexExploreScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~HexExploreScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override;\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    [[nodiscard]] float trueObjective(int) const override { return solved; }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        return {{Str::exploreSolved, 5.0f}};\n    }\n\nprivate:\n    bool solved = false;\n\n    HexagonalMazeComponent maze;\n\n    Magnum::Vector3 rewardObjectCoords;\n    Object3D *rewardObject = nullptr;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_hex_memory.hpp",
    "content": "#pragma once\n\n#include <list>\n\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/component_hexagonal_maze.hpp>\n\nnamespace Megaverse\n{\n\nstruct CollectableObject\n{\n    Object3D *object = nullptr;\n    bool good = false;\n};\n\nstruct VoxelHexMemory\n{\n    std::list<CollectableObject> objects;\n};\n\n\nclass HexMemoryScenario : public DefaultScenario\n{\npublic:\n    explicit HexMemoryScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~HexMemoryScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override;\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void spawnAgents(std::vector<AbstractAgent *> &agents) override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    [[nodiscard]] float trueObjective(int /*agentIdx*/) const override { return solved; }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        return {\n            {Str::memoryCollectGood, 1.0f},\n            {Str::memoryCollectBad, -1.0f},\n        };\n    }\n\n    float episodeLengthSec() const override\n    {\n        // add a little bit of time for every extra reward object\n        return Scenario::episodeLengthSec() + 3.0f * goodObjects.size();\n    }\n\nprivate:\n    bool solved = false;\n\n    HexagonalMazeComponent maze;\n\n    VoxelGridComponent<VoxelHexMemory> vg;\n\n    Magnum::Vector3 landmarkLocation;\n    std::vector<Magnum::Vector3> goodObjects, badObjects;\n    int goodObjectsCollected = 0;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_obstacles.hpp",
    "content": "#pragma once\n\n#include <scenarios/platforms.hpp>\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/component_platforms.hpp>\n#include <scenarios/component_voxel_grid.hpp>\n#include <scenarios/component_fall_detection.hpp>\n#include <scenarios/component_object_stacking.hpp>\n\n\nnamespace Megaverse\n{\n\nenum class PlatformType { EMPTY, WALL, LAVA, STEP, GAP };\n\nstruct VoxelObstacles : public VoxelWithPhysicsObjects\n{\n    Object3D *rewardObject = nullptr;\n};\n\nclass ObstaclesScenario : public DefaultScenario, public ObjectStackingCallbacks, public FallDetectionCallbacks\n{\npublic:\n    explicit ObstaclesScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override;\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override { return agentSpawnPositions; }\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    float trueObjective(int) const override { return solved; }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        return {\n            {Str::obstaclesAgentAtExit, 1.0f},\n            {Str::obstaclesAllAgentsAtExit, 5.0f},\n            {Str::obstaclesExtraReward, 0.5f},\n            {Str::obstaclesAgentCarriedObjectToExit, 0.0f},\n        };\n    }\n\n    void initializeDefaultParameters() override\n    {\n        DefaultScenario::initializeDefaultParameters();\n\n        platformTypes = {PlatformType::WALL, PlatformType::LAVA, PlatformType::STEP, PlatformType::GAP};\n\n        auto &fp = floatParams;\n        fp[Str::obstaclesMinNumPlatforms] = 1;\n        fp[Str::obstaclesMaxNumPlatforms] = 2;\n\n        fp[Str::obstaclesMinGap] = 1;\n        fp[Str::obstaclesMaxGap] = 2;\n\n        fp[Str::obstaclesMinLava] = 1;\n        fp[Str::obstaclesMaxLava] = 4;\n\n        fp[Str::obstaclesMinHeight] = 1;\n        fp[Str::obstaclesMaxHeight] = 3;\n\n        fp[Str::obstaclesNumAllowedMaxDifficulty] = 1;\n    }\n\n    float episodeLengthSec() const override;\n\n    void agentTouchedLava(int agentIdx);\n\n    void agentFell(int agentIdx) override;\n\nprotected:\n    std::vector<PlatformType> platformTypes;\n\nprivate:\n    VoxelGridComponent<VoxelObstacles> vg;\n    PlatformsComponent platformsComponent;\n    ObjectStackingComponent<VoxelObstacles> objectStackingComponent;\n    FallDetectionComponent<VoxelObstacles> fallDetection;\n\n    std::vector<VoxelCoords> objectSpawnPositions, rewardSpawnPositions;\n    std::vector<Magnum::Vector3> agentSpawnPositions;\n\n    std::vector<bool> agentReachedExit;\n    bool solved = false;\n\n    int numPlatforms{};\n};\n\nclass TestScenario : public ObstaclesScenario\n{\npublic:\n    explicit TestScenario(const std::string &name, Env &env, Env::EnvState &envState)\n        : ObstaclesScenario(name, env, envState)\n    {\n    }\n\n    void initializeDefaultParameters() override\n    {\n        ObstaclesScenario::initializeDefaultParameters();\n\n        auto &fp = floatParams;\n        fp[Str::obstaclesMinNumPlatforms] = 0;\n        fp[Str::obstaclesMaxNumPlatforms] = 0;\n        fp[Str::episodeLengthSec] = 6.0f;\n    }\n};\n\nclass ObstaclesEasyScenario : public ObstaclesScenario\n{\npublic:\n    explicit ObstaclesEasyScenario(const std::string &name, Env &env, Env::EnvState &envState)\n    : ObstaclesScenario(name, env, envState)\n    {\n    }\n\n    void initializeDefaultParameters() override\n    {\n        ObstaclesScenario::initializeDefaultParameters();\n\n        auto &fp = floatParams;\n        fp[Str::obstaclesMinNumPlatforms] = 1;\n        fp[Str::obstaclesMaxNumPlatforms] = 2;\n\n        fp[Str::obstaclesMinGap] = 1;\n        fp[Str::obstaclesMaxGap] = 2;\n\n        fp[Str::obstaclesMinLava] = 1;\n        fp[Str::obstaclesMaxLava] = 4;\n\n        fp[Str::obstaclesMinHeight] = 1;\n        fp[Str::obstaclesMaxHeight] = 3;\n    }\n};\n\nclass ObstaclesMediumScenario : public ObstaclesScenario\n{\npublic:\n    explicit ObstaclesMediumScenario(const std::string &name, Env &env, Env::EnvState &envState)\n    : ObstaclesScenario(name, env, envState)\n    {\n    }\n\n    void initializeDefaultParameters() override\n    {\n        ObstaclesScenario::initializeDefaultParameters();\n\n        auto &fp = floatParams;\n        fp[Str::obstaclesMinNumPlatforms] = 2;\n        fp[Str::obstaclesMaxNumPlatforms] = 4;\n\n        fp[Str::obstaclesMinLava] = 2;\n        fp[Str::obstaclesMaxLava] = 5;\n\n        fp[Str::obstaclesMinHeight] = 1;\n        fp[Str::obstaclesMaxHeight] = 3;\n    }\n};\n\nclass ObstaclesHardScenario : public ObstaclesScenario\n{\npublic:\n    explicit ObstaclesHardScenario(const std::string &name, Env &env, Env::EnvState &envState)\n    : ObstaclesScenario(name, env, envState)\n    {\n    }\n\n    void initializeDefaultParameters() override\n    {\n        ObstaclesScenario::initializeDefaultParameters();\n\n        auto &fp = floatParams;\n        fp[Str::obstaclesMinNumPlatforms] = 2;\n        fp[Str::obstaclesMaxNumPlatforms] = 7;\n\n        fp[Str::obstaclesMinGap] = 2;\n        fp[Str::obstaclesMaxGap] = 3;\n\n        fp[Str::obstaclesMinLava] = 3;\n        fp[Str::obstaclesMaxLava] = 10;\n\n        fp[Str::obstaclesMinHeight] = 2;\n        fp[Str::obstaclesMaxHeight] = 4;\n    }\n};\n\nclass ObstaclesOnePlatformTypeScenario : public ObstaclesScenario\n{\npublic:\n    explicit ObstaclesOnePlatformTypeScenario(const std::string &name, Env &env, Env::EnvState &envState)\n        : ObstaclesScenario(name, env, envState)\n    {\n    }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        auto shaping = ObstaclesScenario::defaultRewardShaping();\n        shaping[Str::obstaclesAgentCarriedObjectToExit] = 1.0f;\n        return shaping;\n    }\n\n    void initializeDefaultParameters() override\n    {\n        ObstaclesScenario::initializeDefaultParameters();\n\n        auto &fp = floatParams;\n        fp[Str::obstaclesMinNumPlatforms] = 1;\n        fp[Str::obstaclesMaxNumPlatforms] = 4;\n\n        fp[Str::obstaclesMinGap] = 1;\n        fp[Str::obstaclesMaxGap] = 3;\n        fp[Str::obstaclesMinLava] = 2;\n        fp[Str::obstaclesMaxLava] = 10;\n        fp[Str::obstaclesMinHeight] = 1;\n        fp[Str::obstaclesMaxHeight] = 3;\n\n        fp[Str::obstaclesNumAllowedMaxDifficulty] = 1;\n    }\n};\n\nclass ObstaclesOnlyWallsScenario : public ObstaclesOnePlatformTypeScenario\n{\npublic:\n    explicit ObstaclesOnlyWallsScenario(const std::string &name, Env &env, Env::EnvState &envState)\n        : ObstaclesOnePlatformTypeScenario(name, env, envState)\n    {\n    }\n\n    void initializeDefaultParameters() override\n    {\n        ObstaclesOnePlatformTypeScenario::initializeDefaultParameters();\n        platformTypes = {PlatformType::WALL};\n    }\n};\n\nclass ObstaclesOnlyStepsScenario : public ObstaclesOnePlatformTypeScenario\n{\npublic:\n    explicit ObstaclesOnlyStepsScenario(const std::string &name, Env &env, Env::EnvState &envState)\n        : ObstaclesOnePlatformTypeScenario(name, env, envState)\n    {\n    }\n\n    void initializeDefaultParameters() override\n    {\n        ObstaclesOnePlatformTypeScenario::initializeDefaultParameters();\n        platformTypes = {PlatformType::STEP};\n    }\n};\n\nclass ObstaclesOnlyLavaScenario : public ObstaclesOnePlatformTypeScenario\n{\npublic:\n    explicit ObstaclesOnlyLavaScenario(const std::string &name, Env &env, Env::EnvState &envState)\n        : ObstaclesOnePlatformTypeScenario(name, env, envState)\n    {\n    }\n\n    void initializeDefaultParameters() override\n    {\n        ObstaclesOnePlatformTypeScenario::initializeDefaultParameters();\n        platformTypes = {PlatformType::LAVA};\n    }\n};\n\n}\n"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_rearrange.hpp",
    "content": "#pragma once\n\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/component_platforms.hpp>\n#include <scenarios/component_voxel_grid.hpp>\n#include <scenarios/component_object_stacking.hpp>\n\n\nnamespace Megaverse\n{\n\nstruct VoxelRearrange : public VoxelState\n{\n    RigidBody *physicsObject = nullptr;\n};\n\nstruct ArrangementItem\n{\n    ArrangementItem() = default;\n\n    ArrangementItem(DrawableType shape, ColorRgb color, const VoxelCoords &offset)\n    : shape{shape}\n    , color{color}\n    , offset{offset}\n    {\n    }\n\n    static ArrangementItem random(Rng &rng, const VoxelCoords &offset)\n    {\n        const static std::vector<DrawableType> shapes{\n            DrawableType::Cylinder, DrawableType::Capsule, DrawableType::Box, DrawableType::Sphere,\n        };\n\n\n        const auto shape = randomSample(shapes, rng);\n        const auto color = randomObjectColor(rng);\n\n        ArrangementItem item{shape, color, offset};\n        return item;\n    }\n\npublic:\n    DrawableType shape = DrawableType::Sphere;\n    ColorRgb color = ColorRgb::WHITE;\n    VoxelCoords offset{};\n};\n\nclass ArrangementObject : public RigidBody\n{\npublic:\n    ArrangementObject(Object3D *parent, Magnum::Float mass, btCollisionShape *bShape, btDynamicsWorld &bWorld)\n    : RigidBody{parent, mass, bShape, bWorld}\n    {\n    }\n\npublic:\n    ArrangementItem arrangementItem;\n    bool pickedUp = false;\n};\n\nstruct Arrangement\n{\n    std::vector<ArrangementItem> items;\n\n    bool contains(DrawableType shape, ColorRgb color, const VoxelCoords &offset) const\n    {\n        for (const auto &item : items)\n            if (item.shape == shape && item.color == color && item.offset == offset)\n                return true;\n\n        return false;\n    }\n};\n\nclass RearrangeScenario : public DefaultScenario, public ObjectStackingCallbacks\n{\nprivate:\n    class RearrangePlatform;\n\npublic:\n    explicit RearrangeScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~RearrangeScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override;\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    float trueObjective(int /*agentIdx*/) const override { return solved; }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        return {\n            {Str::rearrangeOneMoreObjectCorrectPosition, 1},\n            {Str::rearrangeAllObjectsCorrectPosition, 10},\n        };\n    }\n\n    void generateArrangement();\n\n    void arrangementDrawables(DrawablesMap &drawables, const Arrangement &arr, VoxelCoords center, bool interactive);\n\n    int countMatchingObjects() const;\n\n    bool canPlaceObject(int /*agentIdx*/, const VoxelCoords &coords, Object3D *obj) override;\n\n    void placedObject(int agentIdx, const VoxelCoords &coords, Object3D *obj) override;\n    void pickedObject(int agentIdx, const VoxelCoords &coords, Object3D *obj) override;\n\n    void checkDone(int agentIdx);\n\nprivate:\n    PlatformsComponent platformsComponent;\n    VoxelGridComponent<VoxelRearrange> vg;\n    ObjectStackingComponent<VoxelRearrange> objectStackingComponent;\n\n    std::unique_ptr<RearrangePlatform> platform;\n\n    Arrangement arrangement;\n    std::vector<ArrangementObject *> arrangementObjects;\n\n    int maxMatchingObjects = 0;\n\n    const VoxelCoords leftCenter = {5, 2, 5};\n    const VoxelCoords rightCenter = {13, 2, 5};\n\n    bool solved = false;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_sokoban.hpp",
    "content": "#pragma once\n\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/component_voxel_grid.hpp>\n#include <scenarios/component_fall_detection.hpp>\n#include <scenarios/component_object_stacking.hpp>\n\n\nnamespace Megaverse\n{\n\nstruct SokobanLevel\n{\n    std::vector<std::string> rows;\n};\n\n\nclass SokobanScenario : public DefaultScenario\n{\npublic:\n    explicit SokobanScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~SokobanScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override;\n\n    void reloadLevels();\n\n    void createLayout();\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    float trueObjective(int) const override { return float(solved); }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        return {\n            {Str::sokobanBoxOnTarget, 1.0f},\n            {Str::sokobanBoxLeavesTarget, -1.0f},\n            {Str::sokobanAllBoxesOnTarget, 10.0f},\n        };\n    }\n\n    void initializeDefaultParameters() override\n    {\n        DefaultScenario::initializeDefaultParameters();\n        floatParams[Str::episodeLengthSec] = 80.0f;\n    }\n\nprivate:\n    std::string boxobanLevelsDir{};\n    std::vector<std::string> allSokobanLevelFiles{};\n    constexpr static ConstStr levelSet = \"unfiltered\", levelSplit = \"train\";\n\n    std::vector<SokobanLevel> levels;\n    SokobanLevel currLevel;\n    int length = 0, width = 0;\n\n    VoxelGridComponent<VoxelWithPhysicsObjects> vg;\n    const float voxelSize = 2;\n\n    std::vector<Magnum::Vector3> agentPositions;\n    std::vector<VoxelCoords> boxesCoords;\n    int numBoxes = 0, numBoxesOnGoal = 0;\n\n    bool solved = false;\n};\n\n}"
  },
  {
    "path": "src/libs/scenarios/include/scenarios/scenario_tower_building.hpp",
    "content": "#pragma once\n\n#include <env/scenario.hpp>\n\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/scenario_default.hpp>\n#include <scenarios/component_platforms.hpp>\n#include <scenarios/component_voxel_grid.hpp>\n#include <scenarios/component_fall_detection.hpp>\n#include <scenarios/component_object_stacking.hpp>\n\n\nnamespace Megaverse\n{\n\nclass TowerBuildingScenario : public DefaultScenario, public ObjectStackingCallbacks, public FallDetectionCallbacks\n{\nprivate:\n    class TowerBuildingPlatform;\n\npublic:\n    struct AgentState\n    {\n        bool pickedUpObject = false;\n        bool visitedBuildingZoneWithObject = false;\n    };\n\npublic:\n    explicit TowerBuildingScenario(const std::string &name, Env &env, Env::EnvState &envState);\n\n    ~TowerBuildingScenario() override;\n\n    // Scenario interface\n    void reset() override;\n\n    void step() override;\n\n    std::vector<Magnum::Vector3> agentStartingPositions() override;\n\n    void addEpisodeDrawables(DrawablesMap &drawables) override;\n\n    float trueObjective(int) const override { return float(highestTower); }\n\n    RewardShaping defaultRewardShaping() const override\n    {\n        return {\n            {Str::teamSpirit, 0.1f},  // replaces the default value\n            {Str::towerPickedUpObject, 0.1f},\n            {Str::towerVisitedBuildingZoneWithObject, 0.1f},\n            {Str::towerBuildingReward, 1.0f},\n        };\n    }\n\n    float episodeLengthSec() const override;\n\n    // Callbacks\n    bool canPlaceObject(int agentIdx, const VoxelCoords &voxel, Object3D *obj) override;\n    void placedObject(int agentIdx, const VoxelCoords &voxel, Object3D *obj) override;\n    void pickedObject(int agentIdx, const VoxelCoords &voxel, Object3D *obj) override;\n\nprivate:\n    bool isInBuildingZone(const VoxelCoords &c) const;\n    float calculateTowerReward() const;\n\n    static float buildingRewardCoeffForHeight(float height);\n    void addCollectiveReward(int agentIdx);\n\nprivate:\n    VoxelGridComponent<VoxelWithPhysicsObjects> vg;\n    ObjectStackingComponent<VoxelWithPhysicsObjects> objectStackingComponent;\n    FallDetectionComponent<VoxelWithPhysicsObjects> fallDetection;\n    PlatformsComponent platformsComponent;\n\n    int highestTower = 0;\n    BoundingBox buildingZone;\n    std::unordered_set<VoxelCoords> objectsInBuildingZone;\n    float currBuildingZoneReward = 0.0f;\n\n    std::vector<AgentState> agentState;\n\n    // previous reward associated with an object (so we can subtract it when we move the object elsewhere)\n    std::map<Object3D *, float> previousReward;\n\n    std::unique_ptr<TowerBuildingPlatform> platform;\n};\n\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/component_hexagonal_maze.cpp",
    "content": "#include <mazes/kruskal.h>\n#include <mazes/honeycombmaze.h>\n\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/component_hexagonal_maze.hpp>\n\n\nusing namespace Magnum;\nusing namespace Megaverse;\n\n\nHexagonalMazeComponent::HexagonalMazeComponent(Megaverse::Scenario &scenario)\n: ScenarioComponent{scenario}\n{\n}\n\nHexagonalMazeComponent::~HexagonalMazeComponent() = default;\n\nvoid HexagonalMazeComponent::reset(Env &, Env::EnvState &envState)\n{\n    mazeSize = randRange(minSize, maxSize, envState.rng);\n    maze = std::make_unique<HoneyCombMaze>(mazeSize);\n\n    Kruskal algorithm;\n\n    TLOG(DEBUG) << \"Initialising graph...\";\n    maze->InitialiseGraph();\n    TLOG(DEBUG) << \"Generating maze...\";\n    maze->GenerateMaze(&algorithm);\n\n    const auto [xmin, ymin, xmax, ymax] = maze->GetCoordinateBounds();\n    xMin = xmin, yMin = ymin, xMax = xmax, yMax = ymax;\n\n    mazeScale = 3.5f;\n    wallHeight = frand(envState.rng) * 0.55f + 0.85f;\n    omitWallsProbability = frand(envState.rng) * (omitWallsProbabilityMax - omitWallsProbabilityMin) + omitWallsProbabilityMin;\n    wallLandmarkProbability = frand(envState.rng) * 0.15f + 0.15f;\n\n    bottomEdgingColor = sampleRandomColor(envState.rng);\n    topEdgingColor = sampleRandomColor(envState.rng);\n\n    xMin *= mazeScale, xMax *= mazeScale, yMin *= mazeScale, yMax *= mazeScale;\n}\n\nvoid HexagonalMazeComponent::addDrawablesAndCollisions(DrawablesMap &drawables, Env::EnvState &envState) const\n{\n    auto scale = Magnum::Vector3{float(xMax - xMin), 0.0001f, float(yMax - yMin)};\n    auto translation = Magnum::Vector3{float(xMax + xMin) / 2, 0.0f, float(yMax + yMin) / 2};\n    addStaticCollidingBox(drawables, envState, scale, translation, randomLayoutColor(envState.rng));\n\n    std::set<std::pair<int, int>> existingWalls;\n\n    auto adjList = maze->getAdjacencyList();\n    for (auto cellIdx = 0; cellIdx < int(adjList.size()); ++cellIdx) {\n        auto &cellAdjList = adjList[cellIdx];\n\n        for (auto &[adjCellIdx, border] : cellAdjList) {\n            auto cellPair = std::make_pair(cellIdx, adjCellIdx);\n            if (cellPair.first > cellPair.second)\n                std::swap(cellPair.first, cellPair.second);  // sort the pair\n\n            // check if this is not an outside border\n            if (adjCellIdx != -1) {\n                if (existingWalls.count(cellPair)) continue;\n\n                if (frand(envState.rng) < omitWallsProbability) {\n                    // remove this particular wall\n                    continue;\n                }\n            }\n\n            existingWalls.insert(cellPair);\n\n            const auto lineBorder = dynamic_cast<LineBorder *>(border.get());\n            auto [x1, z1, x2, z2] = lineBorder->getBorderCoords();\n            x1 *= mazeScale, z1 *= mazeScale, x2 *= mazeScale, z2 *= mazeScale;\n\n            const auto length = 0.5f * sqrtf(float(sqr(x1 - x2) + sqr(z1 - z2)));\n            const Vector3 wallScale{length, wallHeight, 0.15f};\n            const Vector3 wallTranslation{float(x1 + x2) / 2, wallHeight, float(z1 + z2) / 2};\n\n            const auto deltaX = x1 - x2;\n            const auto deltaZ = z1 - z2;\n\n            float rotationY = M_PI_2;\n            if (std::fabs(deltaX) > EPSILON) {\n                const auto tanAlpha = deltaZ / deltaX;\n                rotationY = -atanf(tanAlpha);\n            }\n\n            auto &layoutBox = envState.scene->addChild<Object3D>();\n            if (frand(envState.rng) < wallLandmarkProbability) {\n                const auto landmarkWidth = 0.15f, landmarkHeight = landmarkWidth * length / wallHeight;\n\n                int numLandmarks = randRange(2, 5, envState.rng);\n                for (int li = 0; li < numLandmarks; ++li) {\n                    const Vector3 landmarkScale{landmarkWidth, landmarkHeight, frand(envState.rng) * 1.2f + 1.5f};\n                    auto &landmarkBox = layoutBox.addChild<Object3D>();\n                    const Vector3 landmarkTranslation{float(li % 2 == 1) * landmarkWidth * 2, float(li > 1) * landmarkHeight * 2 - 0.2f, 0};\n                    landmarkBox.scaleLocal(landmarkScale).translate(landmarkTranslation);\n                    drawables[DrawableType::Box].emplace_back(&landmarkBox, rgb(sampleRandomColor(envState.rng)));\n                }\n            }\n\n            layoutBox.scale(wallScale).rotateY(Rad(rotationY)).translate(wallTranslation);\n            drawables[DrawableType::Box].emplace_back(&layoutBox, rgb(ColorRgb::DARK_BLUE));\n\n            auto bBoxShape = std::make_unique<btBoxShape>(btVector3{1, 1, 1});\n            auto &collisionBox = layoutBox.addChild<RigidBody>(envState.scene.get(), 0.0f, bBoxShape.get(), envState.physics->bWorld);\n            collisionBox.syncPose();\n            envState.physics->collisionShapes.emplace_back(std::move(bBoxShape));\n\n            // top and bottom edging\n            {\n                auto &bottomEdgingBox = envState.scene->addChild<Object3D>();\n                const Vector3 edgingScale{length * 1.02f, wallHeight * 0.12f, 0.2f};\n                const Vector3 bottomEdgingTranslation{wallTranslation.x(), edgingScale.y(), wallTranslation.z()};\n                bottomEdgingBox.scale(edgingScale).rotateY(Rad(rotationY)).translate(bottomEdgingTranslation);\n                drawables[DrawableType::Box].emplace_back(&bottomEdgingBox, rgb(bottomEdgingColor));\n\n//                auto &topEdgingBox = envState.scene->addChild<Object3D>();\n//                const Vector3 topEdgingTranslation{wallTranslation.x(), wallHeight * 2, wallTranslation.z()};\n//                topEdgingBox.scale(edgingScale).rotateY(Rad(rotationY)).translate(topEdgingTranslation);\n//                drawables[DrawableType::Box].emplace_back(&topEdgingBox, rgb(topEdgingColor));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/layout_utils.cpp",
    "content": "#include <queue>\n\n#include <util/magnum.hpp>\n#include <util/tiny_logger.hpp>\n\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/component_voxel_grid.hpp>\n\n\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\nusing namespace Megaverse;\n\n\n// TODO: add different types of layouts\nvoid Megaverse::addBoundingBoxes(DrawablesMap &drawables, Env::EnvState &envState, const Boxes &boxes, int voxelType, ColorRgb color, float voxelSize)\n{\n    if (voxelType == VOXEL_EMPTY)\n        return;\n\n    for (auto box : boxes) {\n        const auto bboxMin = box.min, bboxMax = box.max;\n        auto scale = Magnum::Vector3{\n            float(bboxMax.x() - bboxMin.x() + 1) / 2,\n            float(bboxMax.y() - bboxMin.y() + 1) / 2,\n            float(bboxMax.z() - bboxMin.z() + 1) / 2,\n        } * voxelSize;\n\n        auto translation = Magnum::Vector3{\n            float((bboxMin.x() + bboxMax.x())) / 2 + 0.5f,\n            float((bboxMin.y() + bboxMax.y())) / 2 + 0.5f,\n            float((bboxMin.z() + bboxMax.z())) / 2 + 0.5f\n        } * voxelSize;\n\n        auto &layoutBox = envState.scene->addChild<Object3D>();\n        layoutBox.scale(scale).translate(translation);\n\n        if (voxelType & VOXEL_OPAQUE)\n            drawables[DrawableType::Box].emplace_back(&layoutBox, rgb(color));\n\n        if (voxelType & VOXEL_SOLID) {\n            auto bBoxShape = std::make_unique<btBoxShape>(btVector3{1,1,1});\n            auto &collisionBox = layoutBox.addChild<RigidBody>(envState.scene.get(), 0.0f, bBoxShape.get(), envState.physics->bWorld);\n\n            collisionBox.syncPose();\n\n            envState.physics->collisionShapes.emplace_back(std::move(bBoxShape));\n        }\n    }\n}\n\nvoid Megaverse::addTerrain(DrawablesMap &drawables, Env::EnvState &envState, TerrainType type, const BoundingBox &bb, float voxelSize)\n{\n    const auto scale = Vector3(bb.max.x() - bb.min.x(), 1.0, bb.max.z() - bb.min.z()) * voxelSize;\n\n    if (scale.x() > 0) {\n        // otherwise we don't draw anything\n        const auto pos = Magnum::Vector3(bb.min.x() * voxelSize + scale.x() / 2, bb.min.y() * voxelSize, bb.min.z() * voxelSize + scale.z() / 2);\n\n        auto &terrainObject = envState.scene->addChild<Object3D>(envState.scene.get());\n        terrainObject.scale({0.5, 0.025, 0.5}).scale(scale);\n        terrainObject.translate({0.0, 0.025, 0.0});\n        terrainObject.translate(pos);\n\n        drawables[DrawableType::Box].emplace_back(&terrainObject, rgb(terrainColor(type)));\n    }\n}\n\nvoid Megaverse::addStaticCollidingBox(\n    DrawablesMap &drawables, Env::EnvState &envState,\n    Vector3 scale, Vector3 translation, ColorRgb color\n)\n{\n    auto &layoutBox = envState.scene->addChild<Object3D>();\n    layoutBox.scale(scale).translate(translation);\n    drawables[DrawableType::Box].emplace_back(&layoutBox, rgb(color));\n\n    auto bBoxShape = std::make_unique<btBoxShape>(btVector3{1, 1, 1});\n    auto &collisionBox = layoutBox.addChild<RigidBody>(envState.scene.get(), 0.0f, bBoxShape.get(), envState.physics->bWorld);\n    collisionBox.syncPose();\n    envState.physics->collisionShapes.emplace_back(std::move(bBoxShape));\n}\n\nObject3D * Megaverse::addCylinder(DrawablesMap &drawables, Object3D &parent, Magnum::Vector3 translation, Magnum::Vector3 scale, ColorRgb color)\n{\n    auto &rootObject = parent.addChild<Object3D>();\n    rootObject.scale(scale).translate(translation);\n    drawables[DrawableType::Cylinder].emplace_back(&rootObject, rgb(color));\n    return &rootObject;\n}\n\nObject3D * Megaverse::addSphere(DrawablesMap &drawables, Object3D &parent, Magnum::Vector3 translation, Magnum::Vector3 scale, ColorRgb color)\n{\n    auto &rootObject = parent.addChild<Object3D>();\n    rootObject.scale(scale).translate(translation);\n    drawables[DrawableType::Sphere].emplace_back(&rootObject, rgb(color));\n    return &rootObject;\n}\n\nObject3D * Megaverse::addPillar(DrawablesMap &drawables, Object3D &parent, Magnum::Vector3 translation, Magnum::Vector3 scale, ColorRgb color)\n{\n    auto rootObject = addCylinder(drawables, parent, translation, scale, color);\n\n    auto capScale = Vector3 {scale.x() * 1.2f, 0.15f, scale.z() * 1.2f};\n    auto capTranslation = Vector3 {0, 0.47, 0} * scale;\n\n    addCylinder(drawables, parent, translation + capTranslation, capScale, color)->setParentKeepTransformation(rootObject);\n    addCylinder(drawables, parent, translation - capTranslation, capScale, color)->setParentKeepTransformation(rootObject);\n\n    return rootObject;\n}\n\nObject3D * Megaverse::addDiamond(DrawablesMap &drawables, Object3D &parent, Magnum::Vector3 translation, Magnum::Vector3 scale, ColorRgb color)\n{\n    auto &rootObject = parent.addChild<Object3D>();\n    auto &bottomHalf = rootObject.addChild<Object3D>();\n    bottomHalf.rotateXLocal(180.0_degf).translate({0.0f, -1.0f, 0.0f});\n    rootObject.scale(scale);\n    rootObject.translate(translation);\n\n    drawables[DrawableType::Cone].emplace_back(&rootObject, rgb(color));\n    drawables[DrawableType::Cone].emplace_back(&bottomHalf, rgb(color));\n\n    return &rootObject;\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_box_a_gone.cpp",
    "content": "#include <scenarios/scenario_box_a_gone.hpp>\n\n\nusing namespace Megaverse;\n\n\nclass BoxAGoneScenario::BoxAGonePlatform : public EmptyPlatform\n{\npublic:\n    explicit BoxAGonePlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int)\n    : EmptyPlatform(parent, rng, walls, params)\n    {\n    }\n\n    ~BoxAGonePlatform() = default;\n\n    void init() override\n    {\n        height = 8;\n        length = width = platformSize;\n    }\n\n    void generate() override\n    {\n        EmptyPlatform::generate();\n    }\n};\n\n\nBoxAGoneScenario::BoxAGoneScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n, vg{*this, 100, 0, 0, 0, voxelSize}\n, platformsComponent{*this}\n, fallDetection{*this, vg.grid, *this}\n{\n}\n\nBoxAGoneScenario::~BoxAGoneScenario() = default;\n\nvoid BoxAGoneScenario::reset()\n{\n    finished = false;\n\n    vg.reset(env, envState);\n    platformsComponent.reset(env, envState);\n    fallDetection.reset(env, envState);\n\n    disappearingPlatforms.clear(), spawnPositions.clear();\n\n    agentStates = std::vector<AgentState>(env.getNumAgents());\n    platformStates.clear();\n    extraPlatforms.clear();\n\n    platform = std::make_unique<BoxAGonePlatform>(platformsComponent.levelRoot.get(), envState.rng, WALLS_ALL, floatParams, env.getNumAgents());\n    platform->init(), platform->generate();\n    vg.addPlatform(*platform, ColorRgb::LAYOUT_DEFAULT, ColorRgb::LAYOUT_DEFAULT, true);\n\n    const int numLevels = randRange(2, 4, envState.rng);\n\n    const static std::vector<ColorRgb> colors{ColorRgb::ORANGE, ColorRgb::BLUE, ColorRgb::VIOLET};\n    const static auto numColors = colors.size();\n\n    int currLevelHeight = 1;\n    for (int level = 0; level < numLevels; ++level) {\n        const auto color = colors[level % numColors];\n\n        currLevelHeight += randRange(2, 4, envState.rng);\n\n        const auto offset = platformSize / 2;\n        const int levelLength = randRange(10, 19, envState.rng);\n        const int levelWidth = randRange(10, 19, envState.rng);\n        const int startX = offset - levelLength / 2, startZ = offset - levelWidth / 2;\n        const float skipProb = frand(envState.rng) * 0.2f;  // uniformly distributed between 0% and 25%\n\n        for (int x = startX; x < startX + levelLength; ++x)\n            for (int z = startZ; z < startZ + levelWidth; ++z) {\n                // skip some platforms\n                if (frand(envState.rng) < skipProb)\n                    continue;\n\n                VoxelCoords coords{x, currLevelHeight, z};\n                disappearingPlatforms.emplace_back(coords, color);\n\n                if (level == numLevels - 1) {\n                    Magnum::Vector3 v(float(x) + 0.5f, float(currLevelHeight) + 0.5f, float(z) + 0.5f);\n                    spawnPositions.emplace_back(v * voxelSize);\n                }\n            }\n    }\n\n    while (int(spawnPositions.size()) < env.getNumAgents())\n        spawnPositions.emplace_back(spawnPositions[0]);\n\n    std::shuffle(spawnPositions.begin(), spawnPositions.end(), envState.rng);\n}\n\nvoid BoxAGoneScenario::step()\n{\n    int agentsTouchingFloor = 0;\n\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        auto agent = envState.agents[i];\n        const auto t = agent->absoluteTransformation().translation();\n        const auto coords = vg.grid.getCoords(t);\n\n        const bool touchesFloor = coords.y() < 3;\n\n        if (touchesFloor) {\n            rewardTeam(Str::boxagoneTouchedFloor, i, 1);  // the rewards here are purely individual (each agent belongs to their own team, although this can be changed)\n            ++agentsTouchingFloor;\n        }\n        else {\n            rewardTeam(Str::boxagonePerStepReward, i, 1);\n            agentStates[i].secondsBeforeTouchedFloor = envState.currEpisodeSec;\n        }\n\n        auto voxel = vg.grid.get(coords);\n        if (voxel && voxel->disappearingPlatform && agent->onGround()) {\n            if (voxel->disappearingPlatform != agentStates[i].lastPlatform) {\n                // visited new platform\n                // set the timer for the previous visited platform to disappear\n                if (platformStates.count(agentStates[i].lastPlatform)) {\n                    auto &p = platformStates[agentStates[i].lastPlatform];\n                    p.remainingTicks = std::min(p.remainingTicks, 3);\n                }\n\n                // add new platform state\n                if (!platformStates.count(voxel->disappearingPlatform)) {\n                    const static auto ticks = 15;\n                    const auto temporaryPlatform = extraPlatforms.back();\n                    platformStates[voxel->disappearingPlatform] = PlatformState{ticks, coords, temporaryPlatform};\n                    extraPlatforms.pop_back();\n                    extraPlatforms.push_front(temporaryPlatform);\n\n                    const auto platformSc = voxel->disappearingPlatform->absoluteTransformation().scaling();\n                    const auto platformTr = voxel->disappearingPlatform->absoluteTransformation().translation();\n                    temporaryPlatform->resetTransformation();\n                    temporaryPlatform->scale(platformSc * 1.05f);\n                    temporaryPlatform->translate(platformTr);\n                    temporaryPlatform->syncPose();\n\n                    voxel->disappearingPlatform->translate(Magnum::Vector3{300, 300, 300} * voxelSize);  // basically remove from the scene\n                    voxel->disappearingPlatform->syncPose();\n                }\n\n                agentStates[i].lastPlatform = voxel->disappearingPlatform;\n            }\n        }\n    }\n\n    for (auto iter = platformStates.begin(); iter != platformStates.end();) {\n        auto &state = iter->second;\n        auto &tempPlatform = state.temporaryPlatform;\n\n        --state.remainingTicks;\n        if (state.remainingTicks <= 0) {\n            tempPlatform->translate(Magnum::Vector3{300, 300, 300} * voxelSize);  // basically remove from the scene\n            tempPlatform->syncPose();\n            platformStates.erase(iter++);\n            vg.grid.remove(state.coords);\n        } else {\n            if (state.remainingTicks <= 5) {\n                const auto platformSc = tempPlatform->absoluteTransformation().scaling();\n                const auto platformTr = tempPlatform->absoluteTransformation().translation();\n                tempPlatform->resetTransformation().scale(platformSc * 1.03f).translate(platformTr);\n                tempPlatform->syncPose();\n            }\n\n            ++iter;\n        }\n    }\n\n    if (agentsTouchingFloor >= env.getNumAgents() && !finished) {\n        finished = true;\n        doneWithTimer();\n    }\n}\n\nstd::vector<Magnum::Vector3> BoxAGoneScenario::agentStartingPositions()\n{\n    return std::vector<Magnum::Vector3>{spawnPositions.begin(), spawnPositions.begin() + env.getNumAgents()};\n}\n\nvoid BoxAGoneScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    addDrawablesAndCollisionObjectsFromVoxelGrid(vg, drawables, envState, voxelSize);\n\n    // add terrain\n    for (auto &[terrainType, boxes] : platform->terrainBoxes)\n        for (auto &bb : boxes)\n            addTerrain(drawables, envState, terrainType, bb.boundingBox(), voxelSize);\n\n    addDisappearingPlatforms(drawables);\n}\n\nvoid BoxAGoneScenario::addDisappearingPlatforms(DrawablesMap &drawables)\n{\n    auto objSize = 0.42f * voxelSize;\n    auto thicknessRatio = 0.045f;\n    auto objScale = Magnum::Vector3{objSize, objSize * thicknessRatio, objSize};\n\n    for (const auto &[pos, color] : disappearingPlatforms) {\n        auto translation = Magnum::Vector3{float(pos.x()) + 0.5f, float(pos.y()) + 0.5f, float(pos.z()) + 0.5f} * voxelSize;\n\n        auto bBoxShape = std::make_unique<btBoxShape>(btVector3{1, 1, 1});\n\n        auto &object = envState.scene->addChild<RigidBody>(envState.scene.get(), 0.0f, bBoxShape.get(), envState.physics->bWorld);\n        object.scale(objScale).translate(translation);\n        object.syncPose();\n\n        drawables[DrawableType::Box].emplace_back(&object, rgb(color));\n\n        envState.physics->collisionShapes.emplace_back(std::move(bBoxShape));\n\n        VoxelBoxAGone voxelState;\n        voxelState.disappearingPlatform = &object;\n        vg.grid.set(pos, voxelState);\n    }\n\n    for (int i = 0; i < env.getNumAgents() * 3; ++i) {\n        auto translation = Magnum::Vector3{300, 300, 300} * voxelSize;\n        auto bBoxShape = std::make_unique<btBoxShape>(btVector3{1, 1, 1});\n\n        auto &object = envState.scene->addChild<RigidBody>(envState.scene.get(), 0.0f, bBoxShape.get(), envState.physics->bWorld);\n        object.scale(objScale).translate(translation);\n        object.syncPose();\n\n        drawables[DrawableType::Box].emplace_back(&object, rgb(ColorRgb::GREEN));\n        envState.physics->collisionShapes.emplace_back(std::move(bBoxShape));\n\n        extraPlatforms.emplace_back(&object);\n    }\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_collect.cpp",
    "content": "#include <util/perlin_noise.hpp>\n\n#include <scenarios/scenario_collect.hpp>\n\n\nusing namespace Megaverse;\n\nusing namespace Magnum::Math::Literals;\n\nCollectScenario::CollectScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n, vg{*this}\n, objectStackingComponent{*this, env.getNumAgents(), vg.grid, *this}\n, fallDetection{*this, vg.grid, *this}\n{\n}\n\nCollectScenario::~CollectScenario() = default;\n\nvoid CollectScenario::reset()\n{\n    solved = false;\n\n    vg.reset(env, envState);\n    objectStackingComponent.reset(env, envState);\n    fallDetection.reset(env, envState);\n\n    numPositiveRewards = positiveRewardsCollected = 0;\n\n    createLandscape();\n\n    fallDetection.agentInitialPositions = agentPositions;\n}\n\nvoid CollectScenario::createLandscape()\n{\n    auto &rng = envState.rng;\n\n    static const std::vector<ColorRgb> landscapeColors = {\n        ColorRgb::LAYOUT_DEFAULT,\n        ColorRgb::VERY_LIGHT_GREEN,\n        ColorRgb::VERY_LIGHT_BLUE,\n        ColorRgb::VERY_LIGHT_GREY,\n        ColorRgb::VERY_LIGHT_ORANGE,\n        ColorRgb::GREY,\n        ColorRgb::DARK_GREY,\n    };\n    static const std::vector<ColorRgb> floorColors = {\n        ColorRgb::GREY,\n        ColorRgb::DARK_GREY,\n        ColorRgb::DARK_GREY,\n    };\n\n    auto landscapeColor = randomSample(landscapeColors, rng);\n    auto floorColor = randomSample(floorColors, rng);\n\n    constexpr static int maxWidth = 42, maxLength = maxWidth;\n\n    const int width = randRange(8, maxWidth, rng);\n    const int length = randRange(8, maxWidth, rng);\n\n    std::vector<int> spawnHeight(length * width, 1);\n\n    double frequency = double (randRange(1, 100, rng)) / 10.0;\n    // frequency = std::clamp(frequency, 0.1, 64.0);\n\n    const std::int32_t octaves = randRange(1, 10, rng);\n    // octaves = std::clamp(octaves, 1, 16);\n\n    const std::uint32_t seed = randRange(0, 1000000000, rng);\n\n    const siv::PerlinNoise perlin(seed);\n    const double fx = maxLength / frequency;\n    const double fz = maxWidth / frequency;\n\n    const int intensity = randRange(5, 18, rng);\n    const float groundLevel = Megaverse::frand(rng) * 0.5f + 0.2f;\n\n    for (int x = 1; x < length - 1; ++x)\n        for (int z = 1; z < width - 1; ++z) {\n            const double noise = perlin.accumulatedOctaveNoise2D_0_1(x / fx, z / fz, octaves);\n            const double yCoord = intensity * (noise - groundLevel);\n\n            if (yCoord >= 1) {\n                const int yCoordRound = int(lround(yCoord));\n                for (int y = yCoordRound; y >= 1; --y) {\n                    VoxelCoords v{x, y, z};\n                    vg.grid.set(v, makeVoxel<VoxelCollect>(VOXEL_SOLID | VOXEL_OPAQUE, TERRAIN_NONE, landscapeColor));\n                }\n\n                spawnHeight[x * width + z] = yCoordRound + 1;\n            }\n        }\n\n    // floor\n    for (int x = 0; x < length; ++x)\n        for (int z = 0; z < width; ++z)\n            vg.grid.set({x, 0, z}, makeVoxel<VoxelCollect>(VOXEL_SOLID | VOXEL_OPAQUE, TERRAIN_NONE, floorColor));\n\n    std::vector<VoxelCoords> spawnPositions;\n\n    for (int x = 1; x < length - 1; ++x)\n        for (int z = 1; z < width - 1; ++z) {\n            const int y = spawnHeight[x * width + z];\n            spawnPositions.emplace_back(x, y, z);\n        }\n\n    std::shuffle(spawnPositions.begin(), spawnPositions.end(), rng);\n\n    int offset = 0;\n    auto agentIntPositions = std::vector<VoxelCoords>(spawnPositions.begin() + offset, spawnPositions.begin() + offset + env.getNumAgents());\n    agentPositions = toFloat(agentIntPositions);\n    offset += env.getNumAgents();\n\n    int numRewards = randRange(1, int(lround(0.05 * width * length)) + 2, rng);\n    numRewards = std::min(numRewards, int(spawnPositions.size()) - offset);\n    int numRewardsPlacedRandomly = std::max(numRewards / 2, 1);\n\n    // place half of the reward randomly\n    rewardPositions = std::vector<VoxelCoords>(spawnPositions.begin() + offset, spawnPositions.begin() + offset + numRewardsPlacedRandomly);\n    offset += numRewardsPlacedRandomly;\n\n    std::sort(spawnPositions.begin() + offset, spawnPositions.end(), [&](const VoxelCoords &a, const VoxelCoords &b) {\n        int heightA = spawnHeight[a.x() * width + a.z()];\n        int heightB = spawnHeight[b.x() * width + b.z()];\n        if (heightA != heightB)\n            return heightA > heightB;\n        else\n            return false;  // equal\n    });\n\n    rewardPositions.insert(rewardPositions.end(), spawnPositions.begin() + offset, spawnPositions.begin() + offset + (numRewards - numRewardsPlacedRandomly));\n    offset += numRewards - numRewardsPlacedRandomly;\n\n    std::shuffle(spawnPositions.begin() + offset, spawnPositions.end(), rng);\n    auto objectsMin = std::max(3, int(length * width * 0.04));\n    auto objectsMax = std::min(objectsMin + 1, int(lround(0.07 * width * length)) + 2);\n    const int numObjects = std::min(randRange(objectsMin, objectsMax, rng), int(spawnPositions.size()) - offset);\n    if (offset + numObjects < int(spawnPositions.size())) {\n        objectPositions = std::vector<VoxelCoords>(spawnPositions.begin() + offset, spawnPositions.begin() + offset + numObjects);\n        offset += numObjects;\n    }\n}\n\nvoid CollectScenario::step()\n{\n    objectStackingComponent.step(env, envState);\n    fallDetection.step(env, envState);\n\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        const auto agent = envState.agents[i];\n        auto t = agent->absoluteTransformation().translation();\n        VoxelCoords voxel = vg.grid.getCoords(t);\n        auto voxelPtr = vg.grid.get(voxel);\n        if (voxelPtr && voxelPtr->rewardObject) {\n            // TLOG(INFO) << \"Reward \" << voxelPtr->reward;\n            Magnum::Vector3 far = {500, 500, 500};\n            voxelPtr->rewardObject->translate(far);\n\n            if (voxelPtr->reward > 0)\n                ++positiveRewardsCollected;\n\n            if (voxelPtr->reward > 0)\n                rewardTeam(Str::collectSingleGood, i, 1);\n            else if (voxelPtr->reward < 0)\n                rewardTeam(Str::collectSingleBad, i, 1);\n\n            if (positiveRewardsCollected >= numPositiveRewards && !solved) {\n                TLOG(INFO) << \"All rewards collected!\";\n                solved = true;\n                doneWithTimer();\n                rewardTeam(Str::collectAll, i, 1);\n            }\n\n            vg.grid.remove(voxel);\n        }\n    }\n}\n\nstd::vector<Magnum::Vector3> CollectScenario::agentStartingPositions()\n{\n    return agentPositions;\n}\n\nvoid CollectScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    addDrawablesAndCollisionObjectsFromVoxelGrid(vg, drawables, envState, 1);\n\n    objectStackingComponent.addDrawablesAndCollisions(drawables, envState, objectPositions);\n\n    // adding reward objects\n    for (const auto &pos : rewardPositions) {\n        auto translation = Magnum::Vector3{float(pos.x()) + 0.5f, float(pos.y()) + 0.8f, float(pos.z()) + 0.5f};\n\n        auto voxel = makeVoxel<VoxelCollect>(VOXEL_EMPTY);\n        ColorRgb color;\n\n        if (frand(envState.rng) > 0.3f) {\n            voxel.reward = +1;\n            color = ColorRgb::GREEN;\n            ++numPositiveRewards;\n        } else {\n            voxel.reward = -1;\n            color = ColorRgb::RED;\n        }\n\n        auto rewardObject = addDiamond(drawables, *envState.scene, translation, {0.17f, 0.45f, 0.17f}, color);\n        voxel.rewardObject = rewardObject;\n\n        vg.grid.set(pos, voxel);\n    }\n}\n\nvoid CollectScenario::agentFell(int agentIdx)\n{\n    // this is just to help agents learn a bit faster\n    rewardAgent(Str::collectSingleBad, agentIdx, 1);\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_empty.cpp",
    "content": "#include <scenarios/layout_utils.hpp>\n#include <scenarios/scenario_empty.hpp>\n\n\nusing namespace Megaverse;\n\n\nEmptyScenario::EmptyScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n{\n}\n\nEmptyScenario::~EmptyScenario() = default;\n\nvoid EmptyScenario::reset()\n{\n}\n\nstd::vector<Magnum::Vector3> EmptyScenario::agentStartingPositions()\n{\n    return std::vector<Magnum::Vector3>(env.getNumAgents(), {1, 1, 1});\n}\n\nvoid EmptyScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    addStaticCollidingBox(drawables, envState, {10, 1, 10}, {5, 0, 5}, ColorRgb::BLUE);\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_football.cpp",
    "content": "#include <scenarios/scenario_football.hpp>\n\n\nusing namespace Megaverse;\n\n\nclass FootballScenario::FootballLayout : public EmptyPlatform\n{\npublic:\n    FootballLayout(Object3D *parent, Rng &rng, int walls, const FloatParams &params)\n    : EmptyPlatform{parent, rng, walls, params}\n    {\n    }\n\n    void init() override\n    {\n        length = randRange(14, 24, rng);\n        if (width == -1)\n            width = randRange(12, 24, rng);\n\n         height = randRange(3, 7, rng);\n    }\n};\n\n\n// TODO: refactor this?\nclass DynamicRigidBody : public Object3D\n{\npublic:\n    DynamicRigidBody(Object3D *parent, Magnum::Float mass, btCollisionShape *bShape, btDynamicsWorld &bWorld)\n        : Object3D{parent}, bWorld(bWorld)\n    {\n        /* Calculate inertia so the object reacts as it should with\n           rotation and everything */\n        btVector3 bInertia(0.0f, 0.0f, 0.0f);\n        if (!Magnum::Math::TypeTraits<Magnum::Float>::equals(mass, 0.0f))\n            bShape->calculateLocalInertia(mass, bInertia);\n\n        // Bullet rigid body setup\n        motionState = std::make_unique<Magnum::BulletIntegration::MotionState>(*this);\n        auto info = btRigidBody::btRigidBodyConstructionInfo{mass, &motionState->btMotionState(), bShape, bInertia};\n        info.m_friction = 0.5;\n        info.m_rollingFriction = 0.1;\n        info.m_spinningFriction = 0.1;\n\n        bRigidBody.emplace(info);\n//        bRigidBody->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);\n        bRigidBody->forceActivationState(DISABLE_DEACTIVATION);  // do we need this?\n        bWorld.addRigidBody(bRigidBody.get());\n//        auto mask = bRigidBody->getBroadphaseHandle()->m_collisionFilterMask;\n        colliding = true;\n    }\n\n    ~DynamicRigidBody() override\n    {\n        if (colliding)\n            bWorld.removeRigidBody(bRigidBody.get());\n\n        bRigidBody.reset();\n    }\n\n    btRigidBody &rigidBody() { return *bRigidBody; }\n\n    /**\n     * Allows to set collsion shape scale relative to the object scale\n     */\n    void setCollisionScale(const Magnum::Vector3 &scale)\n    {\n        collisionScale = scale;\n    }\n\n    /* needed after changing the pose from Magnum side */\n    void syncPose()\n    {\n        const auto &m = absoluteTransformationMatrix();\n        bRigidBody->setWorldTransform(btTransform{btMatrix3x3{m.rotation()}, btVector3{m.translation()}});\n        bRigidBody->getCollisionShape()->setLocalScaling(btVector3{m.scaling() * collisionScale});\n    }\n\n    void toggleCollision()\n    {\n//        bRigidBody->setCollisionFlags(bRigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);\n//        bRigidBody->setActivationState(DISABLE_SIMULATION);\n\n        if (colliding) {\n            bWorld.removeRigidBody(bRigidBody.get());\n            colliding = false;\n        } else {\n            bWorld.addRigidBody(bRigidBody.get());\n            colliding = true;\n        }\n    }\n\npublic:\n    btDynamicsWorld &bWorld;\n    Magnum::Containers::Pointer<btRigidBody> bRigidBody;\n    std::unique_ptr<Magnum::BulletIntegration::MotionState> motionState;\n    Magnum::Vector3 collisionScale{1, 1, 1};\n    bool colliding = false;\n};\n\n\nFootballScenario::FootballScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n, vg{*this}\n, platformsComponent{*this}\n{\n}\n\nFootballScenario::~FootballScenario() = default;\n\nvoid FootballScenario::reset()\n{\n    vg.reset(env, envState);\n    platformsComponent.reset(env, envState);\n\n    collisionShape = std::make_unique<btSphereShape>(2.0);\n\n    auto &object = envState.scene->addChild<DynamicRigidBody>(envState.scene.get(), 1.0f, collisionShape.get(), envState.physics->bWorld);\n    auto translation = Magnum::Vector3{5, 5, 5};\n    object.scale({0.5, 0.5, 0.5}).translate(translation);\n    object.syncPose();\n\n    footballObject = &object;\n\n    layout = std::make_unique<FootballLayout>(platformsComponent.levelRoot.get(), envState.rng, WALLS_ALL, floatParams);\n    layout->init(), layout->generate();\n    vg.addPlatform(*layout, ColorRgb::LAYOUT_DEFAULT, ColorRgb::LAYOUT_DEFAULT, true);\n}\n\nstd::vector<Magnum::Vector3> FootballScenario::agentStartingPositions()\n{\n    return layout->agentSpawnPoints(env.getNumAgents());\n}\n\nvoid FootballScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    addDrawablesAndCollisionObjectsFromVoxelGrid(vg, drawables, envState, 1);\n\n    drawables[DrawableType::Sphere].emplace_back(footballObject, rgb(ColorRgb::ORANGE));\n}\n\nvoid FootballScenario::step()\n{\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        const auto a = envState.currAction[i];\n        if (!!(a & Action::Interact)) {\n            const auto &agent = envState.agents[i];\n            const auto t = agent->transformation().translation();\n\n            const auto ft = footballObject->transformation().translation();\n\n            auto dt = ft - t;\n            if (dt.length() < 1.8) {\n                auto dtNorm = dt.normalized();\n                dtNorm.y() = 0.5;\n                auto force = 70 * btVector3{dtNorm.x(), dtNorm.y(), dtNorm.z()};\n\n                auto football = dynamic_cast<DynamicRigidBody *>(footballObject);\n                football->bRigidBody->applyForce(force, {0, 0, 0});\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_hex_explore.cpp",
    "content": "#include <mazes/honeycombmaze.h>\n\n#include <scenarios/const.hpp>\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/scenario_hex_explore.hpp>\n\nusing namespace Megaverse;\n\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\n\nHexExploreScenario::HexExploreScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n, maze{*this}\n{\n}\n\nHexExploreScenario::~HexExploreScenario() = default;\n\nvoid HexExploreScenario::reset()\n{\n    solved = false;\n\n    maze.minSize = 2, maze.maxSize = 8;\n    maze.omitWallsProbabilityMin = 0.1f, maze.omitWallsProbabilityMax = 0.4f;\n    maze.reset(env, envState);\n\n    auto &hexMaze = maze.getMaze();\n    auto &adjList = hexMaze.getAdjacencyList();\n\n    auto mazeScale = maze.getScale();\n\n    auto randomCellIdx = randRange(0, adjList.size(), envState.rng);\n    auto cellCenter = hexMaze.getCellCenters()[randomCellIdx];\n\n    rewardObjectCoords = Magnum::Vector3{float(cellCenter.first) * mazeScale, 0, float(cellCenter.second) * mazeScale};\n\n    rewardObject = nullptr;\n}\n\nvoid HexExploreScenario::step()\n{\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        auto &agent = env.getAgents()[i];\n        const auto t = agent->absoluteTransformation().translation();\n\n        const auto threshold = 1.2;\n        const auto distance = (t - rewardObjectCoords).length();\n        if (distance < threshold && !solved) {\n            solved = true;\n            doneWithTimer();\n            rewardTeam(Str::exploreSolved, i, 1);\n            rewardObject->translate({1e3, 1e3, 1e3});\n            break;\n        }\n    }\n}\n\nstd::vector<Magnum::Vector3> HexExploreScenario::agentStartingPositions()\n{\n    std::vector<Magnum::Vector3> positions;\n\n    auto &hexMaze = maze.getMaze();\n    auto mazeScale = maze.getScale();\n    std::vector<int> cellIndices(hexMaze.getAdjacencyList().size(), 0);\n    std::iota(cellIndices.begin(), cellIndices.end(), 0);\n    std::shuffle(cellIndices.begin(), cellIndices.end(), envState.rng);\n\n    float furtherstDistance = 0;\n\n    for (auto cellIdx : cellIndices) {\n        auto cellCenter = hexMaze.getCellCenters()[cellIdx];\n\n        auto spawnPos = Vector3{float(cellCenter.first) * mazeScale, 0.1, float(cellCenter.second) * mazeScale};\n        auto distance = (rewardObjectCoords - spawnPos).length();\n        auto rotation = float(2 * M_PI / env.getNumAgents());\n\n        if (distance > furtherstDistance) {\n            positions.clear();\n            for (int i = 0; i < env.getNumAgents(); ++i) {\n                auto delta = Vector3{sinf(float(i) * rotation), 0, cosf(float(i) * rotation)};\n                positions.emplace_back(spawnPos + delta);\n            }\n\n            furtherstDistance = distance;\n        }\n\n        if (distance > float(maze.getSize()) * maze.getScale())\n            break;\n    }\n\n    if (positions.empty()) {\n        TLOG(DEBUG) << \"Could not generate valid spawn positions for the agents\";\n        positions = std::vector<Vector3>(env.getNumAgents(), Vector3{0, 1, 0});\n    }\n\n    return positions;\n}\n\nvoid HexExploreScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    maze.addDrawablesAndCollisions(drawables, envState);\n\n    // adding reward object\n    const auto scale = 1.9f;\n    rewardObject = addDiamond(drawables, *envState.scene, rewardObjectCoords + Vector3{0, 1.2, 0}, {0.17f * scale, 0.35f * scale, 0.17f * scale}, ColorRgb::VIOLET);\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_hex_memory.cpp",
    "content": "#include <mazes/honeycombmaze.h>\n\n#include <scenarios/layout_utils.hpp>\n#include <scenarios/scenario_hex_memory.hpp>\n\nusing namespace Magnum;\n\nusing namespace Megaverse;\n\n\nHexMemoryScenario::HexMemoryScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n, maze{*this}\n, vg{*this, 100, 0, 0, 0, 1.0}\n{\n}\n\nHexMemoryScenario::~HexMemoryScenario() = default;\n\nvoid HexMemoryScenario::reset()\n{\n    solved = false;\n\n    vg.reset(env, envState);\n\n    goodObjects.clear(), badObjects.clear();\n    goodObjectsCollected = 0;\n\n    maze.minSize = 2, maze.maxSize = 8;\n    maze.omitWallsProbabilityMin = 0.1f, maze.omitWallsProbabilityMax = 0.95f;\n    maze.reset(env, envState);\n\n    auto &hexMaze = maze.getMaze();\n    auto &adjList = hexMaze.getAdjacencyList();\n\n    auto mazeScale = maze.getScale();\n\n    float minDistanceToCenter = 1e9f;\n    int centerCellIdx = 0;\n\n    // hacky way to find the cell closest to center\n    for (int cellIdx = 0; cellIdx < int(adjList.size()); ++cellIdx) {\n        auto cellCenter = hexMaze.getCellCenters()[cellIdx];\n        auto distanceToCenter = sqrt(sqr(cellCenter.first) + sqr(cellCenter.second));\n\n        if (distanceToCenter < minDistanceToCenter) {\n            centerCellIdx = cellIdx;\n            minDistanceToCenter = distanceToCenter;\n        }\n    }\n\n    auto mazeCenter = hexMaze.getCellCenters()[centerCellIdx];\n    landmarkLocation = Magnum::Vector3(mazeCenter.first * mazeScale, 1.0f, mazeCenter.second * mazeScale);\n\n    std::vector<Magnum::Vector3> objectCoordinates;\n\n    for (int cellIdx = 0; cellIdx < int(adjList.size()); ++cellIdx) {\n        if (cellIdx == centerCellIdx)\n            continue;\n\n        auto cellCenter = hexMaze.getCellCenters()[cellIdx];\n        auto coord = Magnum::Vector3(cellCenter.first, 0.5f, cellCenter.second);\n        auto offset = Magnum::Vector3(frand(envState.rng) - 0.5f, 0, frand(envState.rng) - 0.5f);\n        coord += offset;\n        objectCoordinates.emplace_back(coord.x() * mazeScale, coord.y(), coord.z() * mazeScale);\n    }\n\n    std::shuffle(objectCoordinates.begin(), objectCoordinates.end(), envState.rng);\n\n    float cellWithObjectsFraction = frand(envState.rng) * 0.25f + 0.2f;\n    long numCellsWithGoodObjects = std::lround(ceilf(cellWithObjectsFraction * objectCoordinates.size()));\n    long numCellsWithBadObjects = std::lround(ceilf(cellWithObjectsFraction * objectCoordinates.size()));\n\n    goodObjects = std::vector<Magnum::Vector3>(objectCoordinates.begin(), objectCoordinates.begin() + numCellsWithGoodObjects);\n    if (int(objectCoordinates.size()) >= numCellsWithGoodObjects + numCellsWithBadObjects)\n        badObjects = std::vector<Magnum::Vector3>(objectCoordinates.begin() + numCellsWithGoodObjects, objectCoordinates.begin() + numCellsWithGoodObjects + numCellsWithBadObjects);\n}\n\nvoid HexMemoryScenario::step()\n{\n    constexpr auto collectRadius = 1.0f;\n\n    if (goodObjectsCollected >= int(goodObjects.size()) && !solved) {\n        solved = true;\n        doneWithTimer();\n    }\n\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        auto agent = envState.agents[i];\n        const auto t = agent->absoluteTransformation().translation();\n        const auto agentCoords = vg.grid.getCoords(t);\n\n        // checking the surrounding voxels for objects we can collect\n        // (that's a lot of code, isn't it easier to just check all the objects globally lol)\n\n        for (int dx = -1; dx <= 1; ++dx)\n            for (int dz = -1; dz <= 1; ++dz) {\n                const VoxelCoords coords{agentCoords.x() + dx, agentCoords.y(), agentCoords.z() + dz};\n\n                if (!vg.grid.hasVoxel(coords))\n                    continue;\n\n                const auto voxel = vg.grid.get(coords);\n                for (auto it = voxel->objects.begin(); it != voxel->objects.end();) {\n                    const auto pillarPos = it->object->absoluteTransformation().translation();\n                    const auto distance = (pillarPos - t).length();\n                    if (distance < collectRadius) {\n                        // collecting the object\n                        rewardTeam(it->good ? Str::memoryCollectGood : Str::memoryCollectBad, i, 1);\n\n                        goodObjectsCollected += it->good;\n                        it->object->translate({100, 100, 100});\n                        it = voxel->objects.erase(it);\n                    } else\n                        ++it;\n                }\n            }\n    }\n}\n\nstd::vector<Magnum::Vector3> HexMemoryScenario::agentStartingPositions()\n{\n    const auto rotationBetweenAgents = float(2 * M_PI / env.getNumAgents());\n    std::vector<Magnum::Vector3> pos(env.getNumAgents());\n\n    for (int i = 0; i < env.getNumAgents(); ++i)\n        pos[i] = 1.5f * Magnum::Vector3{sinf(rotationBetweenAgents * float(i)), 0.3, cosf(rotationBetweenAgents * float(i))};\n\n    return pos;\n}\n\nvoid HexMemoryScenario::spawnAgents(std::vector<AbstractAgent *> &agents)\n{\n    const auto numAgents = env.getNumAgents();\n    const auto verticalLookLimitRad = floatParams[Str::verticalLookLimitRad];\n    const auto agentPositions = agentStartingPositions();\n\n    const auto rotationBetweenAgents = float(2 * M_PI / env.getNumAgents());\n\n    for (int i = 0; i < numAgents; ++i) {\n        auto randomRotation = rotationBetweenAgents * i;\n        auto &agent = envState.scene->addChild<DefaultKinematicAgent>(\n            envState.scene.get(), envState.physics->bWorld,\n            Magnum::Vector3{agentPositions[i]} + Magnum::Vector3{0.5, 0.0, 0.5},\n            randomRotation, verticalLookLimitRad\n        );\n        agent.updateTransform();\n\n        agents.emplace_back(&agent);\n    }\n}\n\n\nvoid HexMemoryScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    enum ShapeType {\n        SHAPE_PILLAR,\n        SHAPE_DIAMOND,\n        SHAPE_SPHERE,\n    };\n    const static std::vector<ShapeType> shapes = {SHAPE_PILLAR, SHAPE_DIAMOND, SHAPE_SPHERE};\n\n    auto goodObjectColor = randomObjectColor(envState.rng), badObjectColor = goodObjectColor;\n    auto goodShape = randomSample(shapes, envState.rng), badShape = goodShape;\n\n    while (badObjectColor == goodObjectColor && badShape == goodShape) {\n        badObjectColor = randomObjectColor(envState.rng);\n        badShape = randomSample(shapes, envState.rng);\n    }\n\n    maze.addDrawablesAndCollisions(drawables, envState);\n\n    auto addObject = [&](ShapeType shape, ColorRgb color, const Magnum::Vector3 &loc, const Magnum::Vector3 &scale) -> Object3D * {\n        switch (shape) {\n            case SHAPE_SPHERE:\n                return addSphere(drawables, *envState.scene, loc, scale, color);\n            case SHAPE_DIAMOND:\n                return addDiamond(drawables, *envState.scene, loc, scale, color);\n            case SHAPE_PILLAR:\n            default:\n                return addPillar(drawables, *envState.scene, loc, scale, color);\n        }\n    };\n\n    std::map<ShapeType, Vector3> scale {\n        {SHAPE_SPHERE, {0.75, 0.75, 0.75}},\n        {SHAPE_PILLAR, {0.5, 2, 0.5}},\n        {SHAPE_DIAMOND, Vector3 {0.17f, 0.45f, 0.17f} * 2.2},\n    };\n    std::map<ShapeType, Vector3> shift {\n        {SHAPE_SPHERE, {0.5, 0.1, 0.5}},\n        {SHAPE_PILLAR, {0.5, 0.05, 0.5}},\n        {SHAPE_DIAMOND, {0.5, 0.6, 0.5}},\n    };\n\n    // adding landmark object\n    addObject(goodShape, goodObjectColor, landmarkLocation + shift[goodShape], scale[goodShape]);\n    float objScale = 0.6;\n\n    bool isGood = true;\n    for (const auto &objects : {goodObjects, badObjects}) {\n        for (const auto &coord : objects) {\n            auto shape = isGood ? goodShape : badShape;\n            auto color = isGood ? goodObjectColor : badObjectColor;\n\n            const auto object = addObject(shape, color, coord + shift[shape] * objScale, scale[shape] * objScale);\n\n            const auto voxelCoord = vg.grid.getCoords(coord);\n            if (!vg.grid.hasVoxel(voxelCoord))\n                vg.grid.set(voxelCoord, VoxelHexMemory{});\n\n            vg.grid.get(voxelCoord)->objects.emplace_back(CollectableObject{object, isGood});\n        }\n\n        isGood = !isGood;\n    }\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_obstacles.cpp",
    "content": "#include <set>\n\n#include <Magnum/Math/Angle.h>\n\n#include <scenarios/scenario_obstacles.hpp>\n\n\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\nusing namespace Megaverse;\n\n\nnamespace\n{\n\nstd::unique_ptr<Platform> makePlatform(\n    const std::vector<PlatformType> &platformTypes, Object3D *parent, Rng &rng,\n    int walls, const FloatParams &params, int width\n)\n{\n    const auto platformType = randomSample(platformTypes, rng);\n\n    switch (platformType) {\n        case PlatformType::STEP:\n            return std::make_unique<StepPlatform>(parent, rng, walls, params, width);\n        case PlatformType::GAP:\n            return std::make_unique<GapPlatform>(parent, rng, walls, params, width);\n        case PlatformType::LAVA:\n            return std::make_unique<LavaPlatform>(parent, rng, walls, params, width);\n        case PlatformType::WALL:\n            return std::make_unique<WallPlatform>(parent, rng, walls, params, width);\n        case PlatformType::EMPTY:\n        default:\n            return std::make_unique<EmptyPlatform>(parent, rng, walls, params, width);\n    }\n}\n\n}\n\n\nObstaclesScenario::ObstaclesScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n, vg{*this}\n, platformsComponent{*this}\n, objectStackingComponent{*this, env.getNumAgents(), vg.grid, *this}\n, fallDetection{*this, vg.grid, *this}\n{\n}\n\nvoid ObstaclesScenario::reset()\n{\n    vg.reset(env, envState);\n    platformsComponent.reset(env, envState);\n    objectStackingComponent.reset(env, envState);\n    fallDetection.reset(env, envState);\n\n    agentSpawnPositions.clear(), objectSpawnPositions.clear(), rewardSpawnPositions.clear();\n    agentReachedExit = std::vector<bool>(env.getNumAgents(), false);\n    solved = false;\n\n    auto &platforms = platformsComponent.platforms;\n\n    const bool drawWalls = randRange(0, 2, envState.rng);\n\n    StartPlatform *startPlatform = nullptr;\n\n    // generating the level layout\n    for (int attempt = 0; attempt < 20; ++attempt) {\n        platforms.clear();\n\n        numPlatforms = randRange(\n            int(lround(floatParams[Str::obstaclesMinNumPlatforms])),\n            int(lround(floatParams[Str::obstaclesMaxNumPlatforms])) + 1,\n            envState.rng\n        );\n\n        static const std::vector<int> orientations = {ORIENTATION_STRAIGHT, ORIENTATION_TURN_LEFT, ORIENTATION_TURN_RIGHT};\n\n        auto startPlatformPtr = std::make_unique<StartPlatform>(platformsComponent.levelRoot.get(), envState.rng, floatParams);\n        startPlatformPtr->init(), startPlatformPtr->generate();\n        int requiredWidth = startPlatformPtr->width;\n\n        startPlatform = startPlatformPtr.get();\n        Platform *previousPlatform = startPlatform;\n\n        platformsComponent.addPlatform(std::move(startPlatformPtr));\n\n        int numMaxDifficultyObstacles = 0;\n        int numAllowedMaxDifficultyObstacles = int(floatParams.at(Str::obstaclesNumAllowedMaxDifficulty));\n\n        for (int i = 0; i < numPlatforms; ++i) {\n            auto orientation = randomSample(orientations, envState.rng);\n            requiredWidth = orientation == ORIENTATION_STRAIGHT ? requiredWidth : -1;\n\n            std::unique_ptr<Platform> newPlatform;\n            while (!newPlatform || (newPlatform->isMaxDifficulty() && numMaxDifficultyObstacles >= numAllowedMaxDifficultyObstacles)) {\n                newPlatform = makePlatform(platformTypes, previousPlatform->nextPlatformAnchor, envState.rng, WALLS_WEST | WALLS_EAST, floatParams, requiredWidth);\n                newPlatform->init();\n            }\n\n            if (newPlatform->isMaxDifficulty()) {\n                // TLOG(INFO) << \"Max difficulty obstacle!\";\n                ++numMaxDifficultyObstacles;\n            }\n\n            platformsComponent.addPlatform(std::move(newPlatform));\n\n            auto platform = platforms.back().get();\n            platform->generate();\n\n            switch (orientation) {\n                case ORIENTATION_STRAIGHT:\n                    break;\n                case ORIENTATION_TURN_LEFT:\n                    platform->rotateCCW(previousPlatform->width);\n                    break;\n                case ORIENTATION_TURN_RIGHT:\n                    platform->rotateCW(previousPlatform->width);\n                    break;\n                default:\n                    break;\n            }\n\n            if (orientation != ORIENTATION_STRAIGHT) {\n                int walls = WALLS_NORTH;\n                walls |= orientation == ORIENTATION_TURN_LEFT ? WALLS_WEST : WALLS_EAST;\n                const int w = previousPlatform->width, l = platform->width - 1;\n\n                platformsComponent.addPlatform(std::make_unique<TransitionPlatform>(previousPlatform->nextPlatformAnchor, envState.rng, walls, floatParams, l, w));\n                auto transitionPlatform = platforms.back().get();\n\n                transitionPlatform->init();\n                transitionPlatform->generate();\n            }\n\n            previousPlatform = platform;\n            requiredWidth = platform->width;\n        }\n\n        auto exitPlatformPtr = std::make_unique<ExitPlatform>(previousPlatform->nextPlatformAnchor, envState.rng, floatParams, requiredWidth);\n        exitPlatformPtr->init(), exitPlatformPtr->generate();\n        platformsComponent.addPlatform(std::move(exitPlatformPtr));\n\n        // don't check collisions with self and with the previous platforms (there might be overlap)\n        bool selfCollision = false;\n        for (int j = 0; j < int(platforms.size()) && !selfCollision; ++j) {\n            for (int k = 0; k < j - 2; ++k) {\n                if (platforms[j]->collidesWith(*platforms[k])) {\n                    TLOG(INFO) << \"Platform \" << j << \" collides with \" << k;\n                    selfCollision = true;\n                    break;\n                }\n            }\n        }\n\n        if (selfCollision)\n            TLOG(INFO) << \"Self collision! Attempt \" << attempt << \" re-generate!\";\n        else\n            break;\n    }\n\n    auto layoutColor = randomLayoutColor(envState.rng);\n    auto wallColor = randomLayoutColor(envState.rng);\n    for (auto &p : platforms)\n        vg.addPlatform(*p, layoutColor, wallColor, drawWalls);\n\n    assert(startPlatform);\n    agentSpawnPositions = startPlatform->agentSpawnPoints(env.getNumAgents());\n    fallDetection.agentInitialPositions = agentSpawnPositions;\n\n    // generating movable boxes\n    std::vector<int> numBoxes(platforms.size());\n    for (int i = 1; i < int(platforms.size()); ++i) {\n        const auto n = platforms[i]->requiresMovableBoxesToTraverse();\n        for (int box = 0; box < n; ++box) {\n            const auto platformIdx = randRange(std::max(0, i - 2), i, envState.rng);\n            ++numBoxes[platformIdx];\n        }\n    }\n\n    for (int i = 0; i < int(platforms.size()); ++i) {\n        float randomBoxesFraction = frand(envState.rng) * 0.5f;\n        auto randomBoxes = int(lround(randomBoxesFraction * numBoxes[i])) + randRange(0, 2, envState.rng);\n\n        const auto coords = platforms[i]->generateObjectPositions(numBoxes[i] + randomBoxes);\n        objectSpawnPositions.insert(objectSpawnPositions.end(), coords.cbegin(), coords.cend());\n    }\n\n    for (int i = 1; i < int(platforms.size()) - 1; ++i) {\n        auto numRewardObjects = randRange(0, 2, envState.rng);\n        const auto coords = platforms[i]->generateObjectPositions(numRewardObjects);\n        rewardSpawnPositions.insert(rewardSpawnPositions.end(), coords.cbegin(), coords.cend());\n    }\n}\n\nvoid ObstaclesScenario::step()\n{\n    objectStackingComponent.step(env, envState);\n    fallDetection.step(env, envState);\n\n    int numAgentsAtExit = 0;\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        auto agent = envState.agents[i];\n        const auto t = agent->absoluteTransformation().translation();\n        const auto voxel = vg.grid.getCoords(t);\n\n        if (vg.grid.hasVoxel(voxel)) {\n            const auto terrainType = vg.grid.get(voxel)->terrain;\n            if (terrainType & TERRAIN_EXIT) {\n                ++numAgentsAtExit;\n                if (!agentReachedExit[i]) {\n                    agentReachedExit[i] = true;\n                    rewardTeam(Str::obstaclesAgentAtExit, i, 1);\n\n                    if (objectStackingComponent.agentCarryingObject(i)) {\n                        rewardTeam(Str::obstaclesAgentCarriedObjectToExit, i, 1);\n                        // TLOG(INFO) << \"Carried object to exit\";\n                    }\n                }\n            } else if (terrainType & TERRAIN_LAVA)\n                agentTouchedLava(i);\n\n            // additional reward objects promote exploration\n            auto voxelData = vg.grid.get(voxel);\n            if (voxelData->rewardObject) {\n                voxelData->rewardObject->translate({1000, 1000, 1000});\n                voxelData->rewardObject = nullptr;  // remove the reference, but the object will be later cleaned when we destroy the scene graph\n                rewardTeam(Str::obstaclesExtraReward, i, 1);\n            }\n        }\n    }\n\n    if (numAgentsAtExit == env.getNumAgents() && !solved) {\n        solved = true;\n        doneWithTimer();\n        rewardAll(Str::obstaclesAllAgentsAtExit, 1);\n    }\n}\n\nvoid ObstaclesScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    addDrawablesAndCollisionObjectsFromVoxelGrid(vg, drawables, envState, 1);\n\n    // add terrains\n    for (auto &platform : platformsComponent.platforms)\n        for (auto &[terrainType, boxes] : platform->terrainBoxes)\n            for (auto &bb : boxes)\n                addTerrain(drawables, envState, terrainType, bb.boundingBox());\n\n    objectStackingComponent.addDrawablesAndCollisions(drawables, envState, objectSpawnPositions);\n\n    for (const auto &pos : rewardSpawnPositions) {\n        auto rewardObject = addDiamond(drawables, *envState.scene, Vector3{pos} + Vector3{0.5, 0.7, 0.5}, Vector3{0.17f, 0.45f, 0.17f} * 0.8f, ColorRgb::GREEN);\n        if (!vg.grid.hasVoxel(pos))\n            vg.grid.set(pos, makeVoxel<VoxelObstacles>(VOXEL_EMPTY));\n\n        vg.grid.get(pos)->rewardObject = rewardObject;\n    }\n}\n\nfloat ObstaclesScenario::episodeLengthSec() const\n{\n    const auto minDuration = Scenario::episodeLengthSec();\n    return std::max(minDuration, float(numPlatforms) * 35 + float(objectSpawnPositions.size()) * 1);\n}\n\nvoid ObstaclesScenario::agentFell(int)\n{\n    // we don't penalize the agent for stepping onto lava or falling\n    // otherwise they get discouraged and never even go near these obstacles\n}\n\nvoid ObstaclesScenario::agentTouchedLava(int agentIdx)\n{\n    fallDetection.resetAgent(agentIdx, envState.agents[agentIdx]);\n    agentFell(agentIdx);\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_rearrange.cpp",
    "content": "#include <set>\n#include <queue>\n\n#include <scenarios/scenario_rearrange.hpp>\n\n\nusing namespace Magnum;\nusing namespace Megaverse;\n\n\nclass RearrangeScenario::RearrangePlatform : public EmptyPlatform\n{\npublic:\n    explicit RearrangePlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int)\n    : EmptyPlatform(parent, rng, walls, params)\n    {\n    }\n\n    ~RearrangePlatform() override = default;\n\n    void init() override\n    {\n        height = randRange(4, 7, rng);\n        length = 19;\n        width = 14;\n    }\n\n    void generate() override\n    {\n        EmptyPlatform::generate();\n    }\n};\n\n\nRearrangeScenario::RearrangeScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n, platformsComponent{*this}\n, vg{*this, 100, 0, 0, 0, 1}\n, objectStackingComponent{*this, env.getNumAgents(), vg.grid, *this}\n{\n}\n\nRearrangeScenario::~RearrangeScenario() = default;\n\n\nvoid RearrangeScenario::reset()\n{\n    solved = false;\n\n    vg.reset(env, envState);\n    objectStackingComponent.reset(env, envState);\n    platformsComponent.reset(env, envState);\n\n    platform = std::make_unique<RearrangePlatform>(platformsComponent.levelRoot.get(), envState.rng, WALLS_ALL, floatParams, env.getNumAgents());\n    platform->init(), platform->generate();\n    vg.addPlatform(*platform, ColorRgb::DARK_GREY, ColorRgb::DARK_GREY, randomBool(envState.rng));\n\n    arrangement = Arrangement{};\n    arrangementObjects.clear();\n\n    generateArrangement();\n}\n\nvoid RearrangeScenario::generateArrangement()\n{\n    const int arrangementSize = randRange(2, 8, envState.rng);\n\n    // bfs\n    std::queue<ArrangementItem> q;\n    std::unordered_set<VoxelCoords> used;\n\n    const auto firstItem = ArrangementItem::random(envState.rng, {0, 0, 0});\n    q.push(firstItem);\n    arrangement.items.emplace_back(firstItem);\n    used.insert({0, 0, 0});\n\n    std::vector<VoxelCoords> directions{\n        {-1, 0, 0},\n        {1, 0, 0},\n        {0, 1, 0},\n        {0, 0, -1},\n        {0, 0, 1},\n    };\n\n    while (!q.empty()) {\n        const auto currItem = q.front();\n        q.pop();\n\n        int maxBranches = randRange(1, int(directions.size()) + 1, envState.rng);\n        maxBranches = randRange(1, maxBranches + 1, envState.rng);\n        int numBranches = 0;\n\n        std::shuffle(directions.begin(), directions.end(), envState.rng);\n\n        for (auto dir : directions) {\n            const auto newOffset = currItem.offset + dir;\n            const auto below = newOffset - VoxelCoords {0, 1, 0};\n\n            if (newOffset.y() >= 2 || abs(newOffset.x()) >= 2 || abs(newOffset.z()) >= 2)\n                continue;\n\n            if (used.count(newOffset))\n                continue;\n\n            // item has to be on the floor or on top of another item\n            if (!(newOffset.y() == 0 || used.count(below)))\n                continue;\n\n            const auto newItem = ArrangementItem::random(envState.rng, newOffset);\n            q.push(newItem);\n            arrangement.items.emplace_back(newItem);\n            used.insert(newOffset);\n            ++numBranches;\n            if (numBranches >= maxBranches)\n                break;\n\n            if (int(arrangement.items.size()) >= arrangementSize)\n                break;\n        }\n\n        if (int(arrangement.items.size()) >= arrangementSize)\n            break;\n    }\n}\n\nvoid RearrangeScenario::step()\n{\n    objectStackingComponent.step(env, envState);\n}\n\nbool RearrangeScenario::canPlaceObject(int, const VoxelCoords &coord, Object3D *)\n{\n    const auto delta = coord - rightCenter;\n    return abs(delta.x()) <= 2 && abs(delta.z()) <= 2;\n}\n\nint RearrangeScenario::countMatchingObjects() const\n{\n    int matching = 0;\n    for (const auto *obj : arrangementObjects) {\n        if (obj->pickedUp)\n            continue;\n\n        const auto voxelCoords = vg.grid.getCoords(obj->absoluteTransformation().translation());\n        const auto offset = voxelCoords - rightCenter;\n        if (arrangement.contains(obj->arrangementItem.shape, obj->arrangementItem.color, offset))\n            ++matching;\n    }\n\n    return matching;\n}\n\nvoid RearrangeScenario::placedObject(int agentIdx, const VoxelCoords &, Object3D *obj)\n{\n    dynamic_cast<ArrangementObject *>(obj)->pickedUp = false;\n    checkDone(agentIdx);\n}\n\nvoid RearrangeScenario::pickedObject(int agentIdx, const VoxelCoords &, Object3D *obj)\n{\n    dynamic_cast<ArrangementObject *>(obj)->pickedUp = true;\n    checkDone(agentIdx);\n}\n\nvoid RearrangeScenario::checkDone(int agentIdx)\n{\n    const auto matches = countMatchingObjects();\n\n    if (matches > maxMatchingObjects) {\n        rewardTeam(Str::rearrangeOneMoreObjectCorrectPosition, agentIdx, 1);\n        maxMatchingObjects = matches;\n    }\n\n    if (matches >= int(arrangement.items.size()) && !solved) {\n        solved = true;\n        rewardTeam(Str::rearrangeAllObjectsCorrectPosition, agentIdx, 1);\n        doneWithTimer();\n    }\n}\n\nstd::vector<Magnum::Vector3> RearrangeScenario::agentStartingPositions()\n{\n    auto positions = std::vector<Magnum::Vector3>(env.getNumAgents());\n\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        for (int attempt = 0; attempt < 20; ++attempt) {\n            int agentX = randRange(2, platform->length - 1, envState.rng);\n            int agentZ = randRange(2, platform->width - 1, envState.rng);\n            if (fabs(agentX - leftCenter.x()) < 2 && fabs(agentZ - leftCenter.z()) < 2)\n                continue;\n            if (fabs(agentX - rightCenter.x()) < 2 && fabs(agentZ - rightCenter.z()) < 2)\n                continue;\n\n            positions[i] = Vector3 {float(agentX), 2, float(agentZ)};\n            break;\n        }\n    }\n\n    return positions;\n}\n\nvoid RearrangeScenario::arrangementDrawables(DrawablesMap &drawables, const Arrangement &arr, VoxelCoords center, bool interactive)\n{\n    const static std::map<DrawableType, Vector3> scales {\n        { DrawableType::Sphere, {1, 1, 1}},\n        { DrawableType::Box, {1, 1, 1}},\n        { DrawableType::Capsule, {0.8, 0.5, 0.8}},\n        { DrawableType::Cylinder, {0.9, 2, 0.9}},\n    };\n\n    const auto objSize = 0.45f;\n\n    std::unordered_set<VoxelCoords> occupied;\n    for (const auto &item : arr.items)\n        occupied.insert(item.offset);\n\n    int numUnmovedItems = arr.items.size();\n    if (interactive)\n        numUnmovedItems = randRange(0, arr.items.size(), envState.rng);\n\n    int placedItems = 0;\n\n    for (const auto &item : arr.items) {\n        auto pos = item.offset + center;\n\n        if (interactive && placedItems >= numUnmovedItems) {\n            // random offset\n            VoxelCoords newOffset = item.offset;\n            while (occupied.count(newOffset))\n                newOffset = VoxelCoords{randRange(-2, 3, envState.rng), 0, randRange(-2, 3, envState.rng)};\n\n            pos = newOffset + center;\n            occupied.insert(newOffset);\n        }\n\n        auto translation = Magnum::Vector3{float(pos.x()) + 0.5f, float(pos.y()) + 0.5f, float(pos.z()) + 0.5f};\n\n        auto bBoxShape = std::make_unique<btBoxShape>(btVector3{1, 1, 1});\n\n        auto &object = envState.scene->addChild<ArrangementObject>(envState.scene.get(), 0.0f, bBoxShape.get(), envState.physics->bWorld);\n        object.arrangementItem = item;\n\n        object.scale(scales.at(item.shape) * objSize).translate(translation);\n        if (item.shape == DrawableType::Cylinder)\n            object.setCollisionScale({1, 0.5, 1});\n        else if (item.shape == DrawableType::Capsule)\n            object.setCollisionScale({1, 2, 1});\n\n        object.syncPose();\n\n        drawables[item.shape].emplace_back(&object, rgb(item.color));\n\n        envState.physics->collisionShapes.emplace_back(std::move(bBoxShape));\n\n        if (interactive) {\n            VoxelRearrange voxelState;\n            voxelState.physicsObject = &object;\n            vg.grid.set(pos, voxelState);\n\n            arrangementObjects.emplace_back(&object);\n        }\n\n        ++placedItems;\n    }\n}\n\nvoid RearrangeScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    addDrawablesAndCollisionObjectsFromVoxelGrid(vg, drawables, envState, 1);\n\n    for (int dx = -3; dx <= 3; ++dx)\n        for (int dz = -3; dz <= 3; ++dz) {\n            VoxelRearrange voxelState;\n            voxelState.voxelType = VOXEL_SOLID;\n            vg.grid.set(VoxelCoords {leftCenter.x() + dx, 1, leftCenter.z() + dz}, voxelState);\n            vg.grid.set(VoxelCoords {rightCenter.x() + dx, 1, rightCenter.z() + dz}, voxelState);\n        }\n\n    arrangementDrawables(drawables, arrangement, leftCenter, false);\n    arrangementDrawables(drawables, arrangement, rightCenter, true);\n\n    maxMatchingObjects = countMatchingObjects();\n    TLOG(DEBUG) << \"Initial num matching objects: \" << maxMatchingObjects;\n\n    Vector3 platformCenter = {9.5, 0, 7};\n\n    addStaticCollidingBox(drawables, envState, {8.35, 0.5, 5.65}, Vector3{platformCenter} + Vector3 {0.0, 1, 0.0}, ColorRgb::DARK_GREY);\n\n    // add pedestal for the desired arrangement\n    addStaticCollidingBox(drawables, envState, {3, 0.5, 3}, Vector3{leftCenter} + Vector3 {0.5, -0.5, 0.5}, ColorRgb::LAYOUT_DEFAULT);\n    addStaticCollidingBox(drawables, envState, {1.5, 0.5, 1.5}, Vector3{leftCenter} + Vector3 {0.5, -0.45, 0.5}, ColorRgb::DARK_GREY);\n    addStaticCollidingBox(drawables, envState, {3, 0.5, 3}, Vector3{leftCenter} + Vector3 {1.0, -0.66, 1.0}, ColorRgb::LAYOUT_DEFAULT);\n    addStaticCollidingBox(drawables, envState, {3, 0.5, 3}, Vector3{leftCenter} + Vector3 {1.5, -0.82, 1.5}, ColorRgb::LAYOUT_DEFAULT);\n\n    // add pedestal for the working area\n    addStaticCollidingBox(drawables, envState, {3, 0.5, 3}, Vector3{rightCenter} + Vector3 {0.5, -0.5, 0.5}, ColorRgb::BLUE);\n    addStaticCollidingBox(drawables, envState, {1.5, 0.5, 1.5}, Vector3{rightCenter} + Vector3 {0.5, -0.45, 0.5}, ColorRgb::DARK_GREY);\n    addStaticCollidingBox(drawables, envState, {3, 0.5, 3}, Vector3{rightCenter} + Vector3 {0, -0.66, 1.0}, ColorRgb::BLUE);\n    addStaticCollidingBox(drawables, envState, {3, 0.5, 3}, Vector3{rightCenter} + Vector3 {-0.5, -0.82, 1.5}, ColorRgb::BLUE);\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_sokoban.cpp",
    "content": "#include <regex>\n#include <iomanip>\n\n#include <util/string_utils.hpp>\n#include <util/filesystem_utils.hpp>\n\n#include <scenarios/scenario_sokoban.hpp>\n\n\nusing namespace Megaverse;\nusing namespace Magnum::Math::Literals;\n\n\nnamespace\n{\n\nenum SokobanNotation\n{\n    EMPTY_CELL = ' ',\n    GOAL_CELL = '.',\n    PLAYER_CELL = '@',\n    PLAYER_ON_GOAL = '+',\n    BOX_CELL = '$',\n    BOX_ON_GOAL = '*',\n    WALL_CELL = '#',\n};\n\nenum SokobanTerrain\n{\n    SOKO_EMPTY = 0,\n    SOKO_WALL = 1,\n    SOKO_GOAL = 2,\n};\n\n}\n\n\nSokobanScenario::SokobanScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario(name, env, envState)\n, vg{*this, 100, 0, 0, 0, 2}\n{\n    auto envvarBoxobanPath = std::getenv(\"BOXOBAN_LEVELS\");\n    if (!envvarBoxobanPath || strlen(envvarBoxobanPath) == 0)\n        TLOG(DEBUG) << \"Could not find Boxoban levels through the environment variable 'BOXOBAN_LEVELS'\";\n    else\n        boxobanLevelsDir = envvarBoxobanPath;\n\n    constexpr auto backupLocation = \"~/datasets/boxoban\";\n\n    if (boxobanLevelsDir.empty())\n        boxobanLevelsDir = backupLocation;\n\n    if (contains(boxobanLevelsDir, '~')) {\n        auto envvarHome = std::getenv(\"HOME\");\n        if (!envvarHome || strlen(envvarHome) == 0)\n            TLOG(FATAL) << \"Could not query HOME env var to resolve ~ in the path to Boxoban levels dir\";\n\n        boxobanLevelsDir = std::regex_replace(boxobanLevelsDir, std::regex(\"~\"), envvarHome);\n    }\n\n    auto dirWithLevels = pathJoin(boxobanLevelsDir, levelSet, levelSplit);\n\n    for (int levelFileIdx = 0; levelFileIdx <= 999; ++levelFileIdx) {\n        std::ostringstream ss;\n        ss << std::setw(3) << std::setfill('0') << levelFileIdx << \".txt\";\n        auto levelFilePath = pathJoin(dirWithLevels, ss.str());\n        if (fileExists(levelFilePath))\n            allSokobanLevelFiles.emplace_back(levelFilePath);\n    }\n\n    if (allSokobanLevelFiles.empty())\n        TLOG(FATAL) << \"Could not find any Boxoban levels. Set envvar BOXOBAN_LEVELS or put unzipped Boxoban folder \"\n                       \"(named boxoban) containing unfiltered/medium/hard level splits into ~/datasets\";\n\n    TLOG(INFO) << allSokobanLevelFiles.size() << \" boxoban level files found\";\n}\n\nSokobanScenario::~SokobanScenario() = default;\n\nvoid SokobanScenario::reloadLevels()\n{\n    const auto levelFilePath = randomSample(allSokobanLevelFiles, envState.rng);\n\n    std::vector<char> buffer;\n    const auto bytesRead = readAllBytes(levelFilePath, buffer);\n    if (!bytesRead)\n        TLOG(FATAL) << \"Could not read the level file \" << levelFilePath;\n\n    std::string content{buffer.begin(), buffer.end()};\n    auto lines = splitString(content, \"\\n\");\n    SokobanLevel level;\n    for (int i = 0; i < int(lines.size()); ++i) {\n        if (startsWith(lines[i], \";\")) {\n            if (i > 0) levels.emplace_back(std::move(level));\n            level = SokobanLevel{};\n        } else\n            level.rows.emplace_back(lines[i]);\n    }\n\n    std::shuffle(levels.begin(), levels.end(), envState.rng);\n}\n\nvoid SokobanScenario::reset()\n{\n    vg.reset(env, envState);\n    solved = false;\n    agentPositions.clear(), boxesCoords.clear();\n    length = width = 0;\n    numBoxes = numBoxesOnGoal = 0;\n\n    if (levels.empty())\n        reloadLevels();\n\n    currLevel = levels.back();\n    levels.pop_back();\n\n    createLayout();\n}\n\nvoid SokobanScenario::createLayout()\n{\n    constexpr int wallHeight = 2;\n    auto &g = vg.grid;\n\n    static const std::vector<ColorRgb> floorColors = {\n        ColorRgb::LAYOUT_DEFAULT,\n        ColorRgb::VERY_LIGHT_YELLOW,\n        ColorRgb::VERY_LIGHT_BLUE,\n        ColorRgb::VERY_LIGHT_ORANGE,\n        ColorRgb::DARK_GREY,\n    };\n    auto floorColor = randomSample(floorColors, envState.rng);\n\n    length = int(currLevel.rows.size());\n    for (int x = 0; x < length; ++x) {\n        const auto &row = currLevel.rows[x];\n        width = std::max(width, int(row.size()));\n\n        for (int z = 0; z < int(row.size()); ++z) {\n            g.set({x, 0, z}, makeVoxel<VoxelWithPhysicsObjects>(VOXEL_SOLID | VOXEL_OPAQUE, TERRAIN_NONE, floorColor));\n\n            if (row[z] == WALL_CELL) {\n                for (int y = 1; y <= wallHeight; ++y)\n                    g.set({x, y, z}, makeVoxel<VoxelWithPhysicsObjects>(VOXEL_SOLID));\n\n                g.get(VoxelCoords{x, 1, z})->terrain = SOKO_WALL;\n            }\n\n            if (row[z] == PLAYER_CELL || row[z] == PLAYER_ON_GOAL) {\n                for (int agentIdx = 0; agentIdx < env.getNumAgents(); ++agentIdx) {\n                    const float agentX = float(x) + float(agentIdx % 2) * 0.5f;\n                    const float agentZ = float(z) + float(agentIdx % 4 > 1) * 0.5f;\n                    agentPositions.emplace_back(agentX * voxelSize, voxelSize + 0.3 * float(agentIdx) * voxelSize, agentZ * voxelSize);\n                }\n            }\n\n            if (row[z] == GOAL_CELL || row[z] == PLAYER_ON_GOAL)\n                g.set({x, 1, z}, makeVoxel<VoxelWithPhysicsObjects>(VOXEL_EMPTY, SOKO_GOAL));\n\n            if (row[z] == BOX_CELL || row[z] == BOX_ON_GOAL) {\n                boxesCoords.emplace_back(x, 1, z);\n                ++numBoxes;\n            }\n        }\n    }\n}\n\nvoid SokobanScenario::step()\n{\n    // TODO: in multi-agent envs they can push each other and thus move unmovable boxes. Fix\n\n    // moving the boxes logic\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        const auto a = envState.currAction[i];\n        auto &agent = envState.agents[i];\n\n        if (!!(a & Action::Interact)) {\n            auto t = agent->interactLocation()->absoluteTransformation().translation();\n            auto voxel = vg.grid.getWithVector(t);\n\n            if (voxel && voxel->physicsObject) {\n                const auto boxPos = vg.grid.getCoords(t);\n                const auto agentPos = vg.grid.getCoords(agent->absoluteTransformation().translation());\n                const auto dist = manhattanDistance(agentPos, boxPos);\n\n                if (dist == 1) {\n                    // only move the box if we are in the adjacent cell\n                    auto deltaPos = boxPos - agentPos;\n                    auto desiredPos = boxPos + deltaPos;\n\n                    bool occupied = false;\n                    for (int j = 0; j < env.getNumAgents(); ++j)\n                        if (vg.grid.getCoords(envState.agents[j]->absoluteTransformation().translation()) == desiredPos) {\n                            occupied = true;\n                            break;\n                        }\n\n                    if (!occupied) {\n                        if (!vg.grid.hasVoxel(desiredPos))\n                            vg.grid.set(desiredPos, makeVoxel<VoxelWithPhysicsObjects>(VOXEL_EMPTY));\n\n                        auto desiredPosVoxel = vg.grid.get(desiredPos);\n                        if (desiredPosVoxel->terrain != SOKO_WALL && !desiredPosVoxel->physicsObject) {\n                            desiredPosVoxel->physicsObject = voxel->physicsObject;\n                            desiredPosVoxel->physicsObject->parent()->translate(Magnum::Vector3{deltaPos} * voxelSize);\n                            desiredPosVoxel->physicsObject->syncPose();\n                            voxel->physicsObject = nullptr;\n\n                            // moved the box\n                            if (voxel->terrain != SOKO_GOAL && desiredPosVoxel->terrain == SOKO_GOAL) {\n                                // moved the box to the goal position\n                                ++numBoxesOnGoal;\n                                rewardTeam(Str::sokobanBoxOnTarget, i, 1);\n\n                                if (numBoxesOnGoal == numBoxes && !solved) {\n                                    TLOG(INFO) << \"Done!\";\n                                    solved = true;\n                                    rewardTeam(Str::sokobanAllBoxesOnTarget, i, 1);\n                                    doneWithTimer();\n                                }\n\n                            } else if (voxel->terrain == SOKO_GOAL && desiredPosVoxel->terrain != SOKO_GOAL) {\n                                // moved the box from the goal position - penalty\n                                --numBoxesOnGoal;\n                                rewardTeam(Str::sokobanBoxLeavesTarget, i, 1);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nstd::vector<Magnum::Vector3> SokobanScenario::agentStartingPositions()\n{\n    return agentPositions;\n}\n\nvoid SokobanScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    addDrawablesAndCollisionObjectsFromVoxelGrid(vg, drawables, envState, vg.grid.getVoxelSize());\n\n    const static std::map<SokobanTerrain, ColorRgb> colors = {\n        {SOKO_WALL, ColorRgb::LIGHT_ORANGE},\n        {SOKO_GOAL, ColorRgb::LIGHT_GREEN},\n    };\n\n    const static std::map<SokobanTerrain, float> height = {\n        {SOKO_WALL, 0.35f},\n        {SOKO_GOAL, 0.025f},\n    };\n\n    auto &g = vg.grid;\n    for (int x = 0; x < length; ++x) {\n        for (int z = 0; z < width; ++z) {\n            if (!g.hasVoxel({x, 1, z}))\n                continue;\n            auto v = g.get({x, 1, z});\n            if (v->terrain == SOKO_EMPTY)\n                continue;\n\n            const auto pos = Magnum::Vector3(voxelSize * float(x) + voxelSize / 2, voxelSize, voxelSize * float(z) + voxelSize / 2);\n            const auto h = height.at(SokobanTerrain(v->terrain));\n\n            auto &terrainObject = envState.scene->addChild<Object3D>(envState.scene.get());\n            terrainObject.scale({1, h, 1});\n            terrainObject.translate({0.0, h, 0.0});\n            terrainObject.translate(pos);\n\n            drawables[DrawableType::Box].emplace_back(&terrainObject, rgb(colors.at(SokobanTerrain(v->terrain))));\n        }\n    }\n\n    for (auto box : boxesCoords) {\n        auto scale = Magnum::Vector3{voxelSize / 2, 0.45f, voxelSize / 2} * 0.8f;\n        auto translation = Magnum::Vector3{float(box.x()) + 0.5f, float(box.y()) + 0.2f, float(box.z()) + 0.5f} * voxelSize;\n\n        auto &layoutBox = envState.scene->addChild<Object3D>();\n        layoutBox.scale(scale).translate(translation);\n        drawables[DrawableType::Box].emplace_back(&layoutBox, rgb(ColorRgb::DARK_BLUE));\n\n        auto bBoxShape = std::make_unique<btBoxShape>(btVector3{1, 1, 1});\n        auto &collisionBox = layoutBox.addChild<RigidBody>(envState.scene.get(), 0.0f, bBoxShape.get(), envState.physics->bWorld);\n        collisionBox.setCollisionScale({1.15, 3, 1.15});\n        collisionBox.setCollisionOffset({0, 0.6, 0});\n        collisionBox.syncPose();\n        envState.physics->collisionShapes.emplace_back(std::move(bBoxShape));\n\n        if (!g.hasVoxel({box}))\n            g.set(box, makeVoxel<VoxelWithPhysicsObjects>(VOXEL_EMPTY));\n\n        g.get(box)->physicsObject = &collisionBox;\n    }\n}\n"
  },
  {
    "path": "src/libs/scenarios/src/scenario_tower_building.cpp",
    "content": "#include <scenarios/const.hpp>\n#include <scenarios/scenario_tower_building.hpp>\n\n\nusing namespace Megaverse;\n\n\nclass TowerBuildingScenario::TowerBuildingPlatform : public EmptyPlatform\n{\npublic:\n    explicit TowerBuildingPlatform(Object3D *parent, Rng &rng, int walls, const FloatParams &params, int numAgents)\n    : EmptyPlatform(parent, rng, walls, params)\n    , numAgents{numAgents}\n    {\n    }\n\n    ~TowerBuildingPlatform() override = default;\n\n    void init() override\n    {\n        height = randRange(5, 7, rng);\n        length = randRange(12, 30, rng);\n        width = randRange(12, 25, rng);\n\n        // determine the size and the position of the building zone\n        buildZoneLength = randRange(3, 9, rng);\n        buildZoneWidth = randRange(3, 9, rng);\n\n        materialsLength = randRange(2, 8, rng);\n        materialsWidth = randRange(2, 8, rng);\n\n        length = std::max(buildZoneLength + materialsLength + 3, length);\n        width = std::max(buildZoneWidth + materialsWidth + 3, width);\n\n        buildZoneXOffset = randRange(1, length - buildZoneLength - 1, rng);\n        buildZoneZOffset = randRange(1, width - buildZoneWidth - 1, rng);\n\n        materialsXOffset = randRange(1, length - materialsLength - 1, rng);\n        materialsZOffset = randRange(1, width - materialsWidth - 1, rng);\n\n        std::vector<VoxelCoords> spawnCandidates;\n        for (int x = 1; x < length - 1; ++x)\n            for (int z = 1; z < width - 1; ++z)\n                spawnCandidates.emplace_back(x, 2, z);\n\n        std::shuffle(spawnCandidates.begin(), spawnCandidates.end(), rng);\n\n        agentSpawnCoords = toFloat(std::vector<VoxelCoords>(\n            spawnCandidates.begin(), spawnCandidates.begin() + std::min(numAgents, int(spawnCandidates.size()))\n        ));\n        auto spawnIdx = int(agentSpawnCoords.size());\n\n        const auto maxRandomObjects = std::min(int(spawnCandidates.size()) - numAgents, 25);\n        const auto spawnObjects = randRange(0, std::max(1, maxRandomObjects), rng);\n\n        // spawn a bunch of random objects\n        objectSpawnCoords = std::vector<VoxelCoords>(\n            spawnCandidates.begin() + spawnIdx, spawnCandidates.begin() + spawnIdx + spawnObjects\n        );\n\n        // objects that are within the \"materials\" rectangle will be at y=2, otherwise drop them on the floor\n        for (auto &c : objectSpawnCoords) {\n            if (c.x() >= materialsXOffset && c.x() < materialsXOffset + materialsLength\n                && c.z() >= materialsZOffset && c.z() < materialsZOffset + materialsWidth) {\n                continue;\n            }\n            c.y() -= 1;  // put the object on the floor\n        }\n\n        // add the main bulk of materials, a random rectangle of boxes\n        for (int x = materialsXOffset; x < materialsXOffset + materialsLength; ++x)\n            for (int y = 1; y <= 1; ++y)\n                for (int z = materialsZOffset; z < materialsZOffset + materialsWidth; ++z)\n                    objectSpawnCoords.emplace_back(x, y, z);\n\n        while (int(agentSpawnCoords.size()) < numAgents)\n        agentSpawnCoords.emplace_back(agentSpawnCoords[0]);\n    }\n\n    void generate() override\n    {\n        EmptyPlatform::generate();\n\n        const VoxelCoords minCoord{buildZoneXOffset, 1, buildZoneZOffset},\n                          maxCoord{buildZoneXOffset + buildZoneLength, 1, buildZoneZOffset + buildZoneWidth};\n\n        MagnumAABB buildingZoneBB{*root, {minCoord, maxCoord}};\n        terrainBoxes[TERRAIN_BUILDING_ZONE].emplace_back(buildingZoneBB);\n    }\n\n    std::vector<Magnum::Vector3> agentSpawnPoints(int /*numAgents*/) override\n    {\n        return agentSpawnCoords;\n    }\n\n    std::vector<VoxelCoords> generateObjectPositions(int /*numBoxesToGenerate*/) override\n    {\n        return objectSpawnCoords;\n    }\n\n    int numMovableBoxes() const\n    {\n        return objectSpawnCoords.size();\n    }\n\nprivate:\n    std::vector<Magnum::Vector3> agentSpawnCoords;\n    std::vector<VoxelCoords> objectSpawnCoords;\n\n    int buildZoneLength{}, buildZoneWidth{}, materialsLength{}, materialsWidth{};\n    int buildZoneXOffset{}, buildZoneZOffset{}, materialsXOffset{}, materialsZOffset{};\n\n    int numAgents{};\n};\n\n\nTowerBuildingScenario::TowerBuildingScenario(const std::string &name, Env &env, Env::EnvState &envState)\n: DefaultScenario{name, env, envState}\n, vg{*this}\n, objectStackingComponent{*this, env.getNumAgents(), vg.grid, *this}\n, fallDetection{*this, vg.grid, *this}\n, platformsComponent{*this}\n, agentState(size_t(env.getNumAgents()))\n{\n}\n\nTowerBuildingScenario::~TowerBuildingScenario() = default;\n\nvoid TowerBuildingScenario::reset()\n{\n    objectStackingComponent.reset(env, envState);\n    vg.reset(env, envState);\n    fallDetection.reset(env, envState);\n    platformsComponent.reset(env, envState);\n\n    std::fill(agentState.begin(), agentState.end(), AgentState{});\n    previousReward.clear();\n\n    auto layoutColor = randomLayoutColor(envState.rng);\n    while (layoutColor == ColorRgb::BUILDING_ZONE)\n        layoutColor = randomLayoutColor(envState.rng);\n\n    platform = std::make_unique<TowerBuildingPlatform>(platformsComponent.levelRoot.get(), envState.rng, WALLS_ALL, floatParams, env.getNumAgents());\n    platform->init(), platform->generate();\n    vg.addPlatform(*platform, layoutColor, randomLayoutColor(envState.rng), randomBool(envState.rng));\n\n    buildingZone = platform->terrainBoxes[TERRAIN_BUILDING_ZONE].front().boundingBox();\n\n    currBuildingZoneReward = 0.0f;\n    objectsInBuildingZone.clear();\n    highestTower = 0;\n\n    fallDetection.agentInitialPositions = agentStartingPositions();\n}\n\nstd::vector<Magnum::Vector3> TowerBuildingScenario::agentStartingPositions()\n{\n    return platform->agentSpawnPoints(env.getNumAgents());\n}\n\nvoid TowerBuildingScenario::addEpisodeDrawables(DrawablesMap &drawables)\n{\n    addDrawablesAndCollisionObjectsFromVoxelGrid(vg, drawables, envState, 1);\n\n    for (auto &[terrainType, boxes] : platform->terrainBoxes)\n        for (auto &bb : boxes)\n            addTerrain(drawables, envState, terrainType, bb.boundingBox());\n\n    const auto objectPositions = platform->generateObjectPositions(-1);\n    for (const auto &pos : objectPositions)\n        if (isInBuildingZone(pos))\n            objectsInBuildingZone.insert(pos);\n    currBuildingZoneReward = calculateTowerReward();\n    TLOG(INFO) << \"Initial tower reward: \" << currBuildingZoneReward;\n\n    objectStackingComponent.addDrawablesAndCollisions(drawables, envState, objectPositions);\n}\n\nvoid TowerBuildingScenario::step()\n{\n    objectStackingComponent.step(env, envState);\n    fallDetection.step(env, envState);\n\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        // reward shaping: give agents reward for visiting bulding zone while carrying the object\n        if (objectStackingComponent.agentCarryingObject(i)) {\n            const auto &agent = envState.agents[i];\n            const auto t = agent->transformation().translation();\n\n            VoxelCoords voxel = vg.grid.getCoords(t);\n            if (isInBuildingZone(voxel)) {\n                if (!agentState[i].visitedBuildingZoneWithObject) {\n                    rewardTeam(Str::towerVisitedBuildingZoneWithObject, i, 1);\n                    agentState[i].visitedBuildingZoneWithObject = true;\n                }\n            }\n        }\n    }\n}\n\nbool TowerBuildingScenario::canPlaceObject(int, const VoxelCoords &c, Object3D *)\n{\n    return isInBuildingZone(c);\n}\n\nvoid TowerBuildingScenario::placedObject(int agentIdx, const VoxelCoords &voxel, Object3D *)\n{\n    if (isInBuildingZone(voxel))\n        objectsInBuildingZone.insert(voxel);\n\n    addCollectiveReward(agentIdx);\n\n    highestTower = std::max(highestTower, voxel.y() - buildingZone.min.y() + 1);\n}\n\nvoid TowerBuildingScenario::pickedObject(int agentIdx, const VoxelCoords &voxel, Object3D *)\n{\n    if (isInBuildingZone(voxel))\n        objectsInBuildingZone.erase(voxel);\n\n    if (!agentState[agentIdx].pickedUpObject) {\n        rewardAgent(Str::towerPickedUpObject, agentIdx, 1);\n        agentState[agentIdx].pickedUpObject = true;\n    }\n}\n\nbool TowerBuildingScenario::isInBuildingZone(const VoxelCoords &c) const\n{\n    return c.x() >= buildingZone.min.x() && c.x() < buildingZone.max.x() && c.z() >= buildingZone.min.z() && c.z() < buildingZone.max.z();\n}\n\nfloat TowerBuildingScenario::calculateTowerReward() const\n{\n    float reward = 0.0f;\n    for (auto &pos : objectsInBuildingZone) {\n        auto height = pos.y();\n        reward += buildingRewardCoeffForHeight(height);\n    }\n\n    return reward;\n}\n\n/**\n * The higher the agents place the blocks the more we reward them.\n */\nfloat TowerBuildingScenario::buildingRewardCoeffForHeight(float height)\n{\n    auto res = height * 0.05f;\n    res += std::min(0.05f * powf(2, height), 20.0f);\n    return res;\n}\n\nvoid TowerBuildingScenario::addCollectiveReward(int agentIdx)\n{\n    auto newReward = calculateTowerReward();\n    auto rewardDelta = newReward - currBuildingZoneReward;\n    // TLOG(INFO) << \"Curr reward: \" << rewardDelta << \" new reward: \" << newReward;\n\n    currBuildingZoneReward = newReward;\n    rewardTeam(Str::towerBuildingReward, agentIdx, rewardDelta);\n}\n\nfloat Megaverse::TowerBuildingScenario::episodeLengthSec() const\n{\n    return Scenario::episodeLengthSec() + 4.0f * float(platform->numMovableBoxes());\n}\n"
  },
  {
    "path": "src/libs/util/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(libutil VERSION 0.1 LANGUAGES CXX)\n\nadd_library_default(util)\ntarget_link_libraries(util PUBLIC Magnum::Magnum)\n"
  },
  {
    "path": "src/libs/util/include/util/argparse.hpp",
    "content": "/*\n  __ _ _ __ __ _ _ __   __ _ _ __ ___  ___\n / _` | '__/ _` | '_ \\ / _` | '__/ __|/ _ \\ Argument Parser for Modern C++\n| (_| | | | (_| | |_) | (_| | |  \\__ \\  __/ http://github.com/p-ranav/argparse\n \\__,_|_|  \\__, | .__/ \\__,_|_|  |___/\\___|\n           |___/|_|\n\nLicensed under the MIT License <http://opensource.org/licenses/MIT>.\nSPDX-License-Identifier: MIT\nCopyright (c) 2019-2021 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>\nand other contributors.\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*/\n#pragma once\n#include <algorithm>\n#include <any>\n#include <cerrno>\n#include <charconv>\n#include <cstdlib>\n#include <functional>\n#include <iostream>\n#include <iterator>\n#include <list>\n#include <map>\n#include <numeric>\n#include <optional>\n#include <sstream>\n#include <stdexcept>\n#include <string>\n#include <string_view>\n#include <tuple>\n#include <type_traits>\n#include <variant>\n#include <vector>\n\nnamespace argparse {\n\nnamespace details { // namespace for helper methods\n\ntemplate <typename T, typename = void>\nstruct is_container : std::false_type {};\n\ntemplate <> struct is_container<std::string> : std::false_type {};\n\ntemplate <typename T>\nstruct is_container<T, std::void_t<typename T::value_type,\n    decltype(std::declval<T>().begin()),\n    decltype(std::declval<T>().end()),\n    decltype(std::declval<T>().size())>>\n    : std::true_type {};\n\ntemplate <typename T>\nstatic constexpr bool is_container_v = is_container<T>::value;\n\ntemplate <typename T, typename = void>\nstruct is_streamable : std::false_type {};\n\ntemplate <typename T>\nstruct is_streamable<\n    T, std::void_t<decltype(std::declval<std::ostream&>() << std::declval<T>())>>\n    : std::true_type {};\n\ntemplate <typename T>\nstatic constexpr bool is_streamable_v = is_streamable<T>::value;\n\ntemplate <typename T>\nstatic constexpr bool is_representable_v =\n    is_streamable_v<T> || is_container_v<T>;\n\nconstexpr std::size_t repr_max_container_size = 5;\n\ntemplate <typename T> std::string repr(T const &val) {\n    if constexpr (std::is_same_v<T, bool>) {\n        return val ? \"true\" : \"false\";\n    } else if constexpr (std::is_convertible_v<T, std::string_view>) {\n        return '\"' + std::string{std::string_view{val}} + '\"';\n    } else if constexpr (is_container_v<T>) {\n        std::stringstream out;\n        out << \"{\";\n        const auto size = val.size();\n        if (size > 1) {\n            out << repr(*val.begin());\n            std::for_each(\n                std::next(val.begin()),\n                std::next(val.begin(), std::min<std::size_t>(size, repr_max_container_size) - 1),\n                [&out](const auto &v) { out << \" \" << repr(v); });\n            if (size <= repr_max_container_size)\n                out << \" \";\n            else\n                out << \"...\";\n        }\n        if (size > 0)\n            out << repr(*std::prev(val.end()));\n        out << \"}\";\n        return out.str();\n    } else if constexpr (is_streamable_v<T>) {\n        std::stringstream out;\n        out << val;\n        return out.str();\n    } else {\n        return \"<not representable>\";\n    }\n}\n\nnamespace {\n\ntemplate <typename T> constexpr bool standard_signed_integer = false;\ntemplate <> constexpr bool standard_signed_integer<signed char> = true;\ntemplate <> constexpr bool standard_signed_integer<short int> = true;\ntemplate <> constexpr bool standard_signed_integer<int> = true;\ntemplate <> constexpr bool standard_signed_integer<long int> = true;\ntemplate <> constexpr bool standard_signed_integer<long long int> = true;\n\ntemplate <typename T> constexpr bool standard_unsigned_integer = false;\ntemplate <> constexpr bool standard_unsigned_integer<unsigned char> = true;\ntemplate <> constexpr bool standard_unsigned_integer<unsigned short int> = true;\ntemplate <> constexpr bool standard_unsigned_integer<unsigned int> = true;\ntemplate <> constexpr bool standard_unsigned_integer<unsigned long int> = true;\ntemplate <>\nconstexpr bool standard_unsigned_integer<unsigned long long int> = true;\n\n} // namespace\n\ntemplate <typename T>\nconstexpr bool standard_integer =\n    standard_signed_integer<T> || standard_unsigned_integer<T>;\n\ntemplate <class F, class Tuple, class Extra, std::size_t... I>\nconstexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x,\n                                             std::index_sequence<I...>) {\n    return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...,\n                       std::forward<Extra>(x));\n}\n\ntemplate <class F, class Tuple, class Extra>\nconstexpr decltype(auto) apply_plus_one(F &&f, Tuple &&t, Extra &&x) {\n    return details::apply_plus_one_impl(\n        std::forward<F>(f), std::forward<Tuple>(t), std::forward<Extra>(x),\n        std::make_index_sequence<\n            std::tuple_size_v<std::remove_reference_t<Tuple>>>{});\n}\n\nconstexpr auto pointer_range(std::string_view s) noexcept {\n    return std::tuple(s.data(), s.data() + s.size());\n}\n\ntemplate <class CharT, class Traits>\nconstexpr bool starts_with(std::basic_string_view<CharT, Traits> prefix,\n                           std::basic_string_view<CharT, Traits> s) noexcept {\n    return s.substr(0, prefix.size()) == prefix;\n}\n\nenum class chars_format {\n    scientific = 0x1,\n    fixed = 0x2,\n    hex = 0x4,\n    general = fixed | scientific\n};\n\nstruct consume_hex_prefix_result {\n    bool is_hexadecimal;\n    std::string_view rest;\n};\n\nusing namespace std::literals;\n\nconstexpr auto consume_hex_prefix(std::string_view s)\n-> consume_hex_prefix_result {\n    if (starts_with(\"0x\"sv, s) || starts_with(\"0X\"sv, s)) {\n        s.remove_prefix(2);\n        return {true, s};\n    } else {\n        return {false, s};\n    }\n}\n\ntemplate <class T, auto Param>\ninline auto do_from_chars(std::string_view s) -> T {\n    T x;\n    auto [first, last] = pointer_range(s);\n    auto [ptr, ec] = std::from_chars(first, last, x, Param);\n    if (ec == std::errc()) {\n        if (ptr == last)\n            return x;\n        else\n            throw std::invalid_argument{\"pattern does not match to the end\"};\n    } else if (ec == std::errc::invalid_argument) {\n        throw std::invalid_argument{\"pattern not found\"};\n    } else if (ec == std::errc::result_out_of_range) {\n        throw std::range_error{\"not representable\"};\n    } else {\n        return x; // unreachable\n    }\n}\n\ntemplate <class T, auto Param = 0> struct parse_number {\n    auto operator()(std::string_view s) -> T {\n        return do_from_chars<T, Param>(s);\n    }\n};\n\ntemplate <class T> struct parse_number<T, 16> {\n    auto operator()(std::string_view s) -> T {\n        if (auto [ok, rest] = consume_hex_prefix(s); ok)\n            return do_from_chars<T, 16>(rest);\n        else\n            throw std::invalid_argument{\"pattern not found\"};\n    }\n};\n\ntemplate <class T> struct parse_number<T> {\n    auto operator()(std::string_view s) -> T {\n        if (auto [ok, rest] = consume_hex_prefix(s); ok)\n            return do_from_chars<T, 16>(rest);\n        else if (starts_with(\"0\"sv, s))\n            return do_from_chars<T, 8>(rest);\n        else\n            return do_from_chars<T, 10>(rest);\n    }\n};\n\nnamespace {\n\ntemplate <class T> constexpr auto generic_strtod = nullptr;\ntemplate <> constexpr auto generic_strtod<float> = strtof;\ntemplate <> constexpr auto generic_strtod<double> = strtod;\ntemplate <> constexpr auto generic_strtod<long double> = strtold;\n\n} // namespace\n\ntemplate <class T> inline auto do_strtod(std::string const &s) -> T {\n    if (isspace(static_cast<unsigned char>(s[0])) || s[0] == '+')\n        throw std::invalid_argument{\"pattern not found\"};\n\n    auto [first, last] = pointer_range(s);\n    char *ptr;\n\n    errno = 0;\n    if (auto x = generic_strtod<T>(first, &ptr); errno == 0) {\n        if (ptr == last)\n            return x;\n        else\n            throw std::invalid_argument{\"pattern does not match to the end\"};\n    } else if (errno == ERANGE) {\n        throw std::range_error{\"not representable\"};\n    } else {\n        return x; // unreachable\n    }\n}\n\ntemplate <class T> struct parse_number<T, chars_format::general> {\n    auto operator()(std::string const &s) -> T {\n        if (auto r = consume_hex_prefix(s); r.is_hexadecimal)\n            throw std::invalid_argument{\n                \"chars_format::general does not parse hexfloat\"};\n\n        return do_strtod<T>(s);\n    }\n};\n\ntemplate <class T> struct parse_number<T, chars_format::hex> {\n    auto operator()(std::string const &s) -> T {\n        if (auto r = consume_hex_prefix(s); !r.is_hexadecimal)\n            throw std::invalid_argument{\"chars_format::hex parses hexfloat\"};\n\n        return do_strtod<T>(s);\n    }\n};\n\ntemplate <class T> struct parse_number<T, chars_format::scientific> {\n    auto operator()(std::string const &s) -> T {\n        if (auto r = consume_hex_prefix(s); r.is_hexadecimal)\n            throw std::invalid_argument{\n                \"chars_format::scientific does not parse hexfloat\"};\n        if (s.find_first_of(\"eE\") == s.npos)\n            throw std::invalid_argument{\n                \"chars_format::scientific requires exponent part\"};\n\n        return do_strtod<T>(s);\n    }\n};\n\ntemplate <class T> struct parse_number<T, chars_format::fixed> {\n    auto operator()(std::string const &s) -> T {\n        if (auto r = consume_hex_prefix(s); r.is_hexadecimal)\n            throw std::invalid_argument{\n                \"chars_format::fixed does not parse hexfloat\"};\n        if (s.find_first_of(\"eE\") != s.npos)\n            throw std::invalid_argument{\n                \"chars_format::fixed does not parse exponent part\"};\n\n        return do_strtod<T>(s);\n    }\n};\n\n} // namespace details\n\nenum class default_arguments : unsigned int {\n    none = 0,\n    help = 1,\n    version = 2,\n    all = help | version,\n};\n\ninline bool operator& (const default_arguments &a, const default_arguments &b) {\n    return static_cast<unsigned int>(a) & static_cast<unsigned int>(b);\n}\n\nclass ArgumentParser;\n\nclass Argument {\n    friend class ArgumentParser;\n    friend auto operator<<(std::ostream &, ArgumentParser const &)\n    -> std::ostream &;\n\n    template <std::size_t N, std::size_t... I>\n    explicit Argument(std::string_view(&&a)[N], std::index_sequence<I...>)\n        : mIsOptional((is_optional(a[I]) || ...)), mIsRequired(false),\n          mIsRepeatable(false), mIsUsed(false) {\n        ((void)mNames.emplace_back(a[I]), ...);\n        std::sort(\n            mNames.begin(), mNames.end(), [](const auto &lhs, const auto &rhs) {\n                return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size();\n            });\n    }\n\npublic:\n    template <std::size_t N>\n    explicit Argument(std::string_view(&&a)[N])\n        : Argument(std::move(a), std::make_index_sequence<N>{}) {}\n\n    Argument &help(std::string aHelp) {\n        mHelp = std::move(aHelp);\n        return *this;\n    }\n\n    template <typename T> Argument &default_value(T &&aDefaultValue) {\n        mDefaultValueRepr = details::repr(aDefaultValue);\n        mDefaultValue = std::forward<T>(aDefaultValue);\n        return *this;\n    }\n\n    Argument &required() {\n        mIsRequired = true;\n        return *this;\n    }\n\n    Argument &implicit_value(std::any aImplicitValue) {\n        mImplicitValue = std::move(aImplicitValue);\n        mNumArgs = 0;\n        return *this;\n    }\n\n    template <class F, class... Args>\n    auto action(F &&aAction, Args &&... aBound)\n    -> std::enable_if_t<std::is_invocable_v<F, Args..., std::string const>,\n        Argument &> {\n        using action_type = std::conditional_t<\n            std::is_void_v<std::invoke_result_t<F, Args..., std::string const>>,\n            void_action, valued_action>;\n        if constexpr (sizeof...(Args) == 0)\n            mAction.emplace<action_type>(std::forward<F>(aAction));\n        else\n            mAction.emplace<action_type>(\n                [f = std::forward<F>(aAction),\n                    tup = std::make_tuple(std::forward<Args>(aBound)...)](\n                    std::string const &opt) mutable {\n                    return details::apply_plus_one(f, tup, opt);\n                });\n        return *this;\n    }\n\n    auto &append() {\n        mIsRepeatable = true;\n        return *this;\n    }\n\n    template <char Shape, typename T>\n    auto scan() -> std::enable_if_t<std::is_arithmetic_v<T>, Argument &> {\n        static_assert(!(std::is_const_v<T> || std::is_volatile_v<T>),\n                      \"T should not be cv-qualified\");\n        auto is_one_of = [](char c, auto... x) constexpr {\n            return ((c == x) || ...);\n        };\n\n        if constexpr (is_one_of(Shape, 'd') && details::standard_integer<T>)\n            action(details::parse_number<T, 10>());\n        else if constexpr (is_one_of(Shape, 'i') && details::standard_integer<T>)\n            action(details::parse_number<T>());\n        else if constexpr (is_one_of(Shape, 'u') &&\n                           details::standard_unsigned_integer<T>)\n            action(details::parse_number<T, 10>());\n        else if constexpr (is_one_of(Shape, 'o') &&\n                           details::standard_unsigned_integer<T>)\n            action(details::parse_number<T, 8>());\n        else if constexpr (is_one_of(Shape, 'x', 'X') &&\n                           details::standard_unsigned_integer<T>)\n            action(details::parse_number<T, 16>());\n        else if constexpr (is_one_of(Shape, 'a', 'A') &&\n                           std::is_floating_point_v<T>)\n            action(details::parse_number<T, details::chars_format::hex>());\n        else if constexpr (is_one_of(Shape, 'e', 'E') &&\n                           std::is_floating_point_v<T>)\n            action(details::parse_number<T, details::chars_format::scientific>());\n        else if constexpr (is_one_of(Shape, 'f', 'F') &&\n                           std::is_floating_point_v<T>)\n            action(details::parse_number<T, details::chars_format::fixed>());\n        else if constexpr (is_one_of(Shape, 'g', 'G') &&\n                           std::is_floating_point_v<T>)\n            action(details::parse_number<T, details::chars_format::general>());\n        else\n            static_assert(alignof(T) == 0, \"No scan specification for T\");\n\n        return *this;\n    }\n\n    Argument &nargs(int aNumArgs) {\n        if (aNumArgs < 0)\n            throw std::logic_error(\"Number of arguments must be non-negative\");\n        mNumArgs = aNumArgs;\n        return *this;\n    }\n\n    Argument &remaining() {\n        mNumArgs = -1;\n        return *this;\n    }\n\n    template <typename Iterator>\n    Iterator consume(Iterator start, Iterator end,\n                     std::string_view usedName = {}) {\n        if (!mIsRepeatable && mIsUsed) {\n            throw std::runtime_error(\"Duplicate argument\");\n        }\n        mIsUsed = true;\n        mUsedName = usedName;\n        if (mNumArgs == 0) {\n            mValues.emplace_back(mImplicitValue);\n            std::visit([](const auto &aAction) { aAction({}); }, mAction);\n            return start;\n        } else if (mNumArgs <= std::distance(start, end)) {\n            if (auto expected = maybe_nargs()) {\n                end = std::next(start, *expected);\n                if (std::any_of(start, end, Argument::is_optional)) {\n                    throw std::runtime_error(\"optional argument in parameter sequence\");\n                }\n            }\n\n            struct action_apply {\n                void operator()(valued_action &f) {\n                    std::transform(first, last, std::back_inserter(self.mValues), f);\n                }\n\n                void operator()(void_action &f) {\n                    std::for_each(first, last, f);\n                    if (!self.mDefaultValue.has_value()) {\n                        if (auto expected = self.maybe_nargs())\n                            self.mValues.resize(*expected);\n                    }\n                }\n\n                Iterator first, last;\n                Argument &self;\n            };\n            std::visit(action_apply{start, end, *this}, mAction);\n            return end;\n        } else if (mDefaultValue.has_value()) {\n            return start;\n        } else {\n            throw std::runtime_error(\"Too few arguments for '\" +\n                                     std::string(mUsedName) + \"'.\");\n        }\n    }\n\n    /*\n     * @throws std::runtime_error if argument values are not valid\n     */\n    void validate() const {\n        if (auto expected = maybe_nargs()) {\n            if (mIsOptional) {\n                if (mIsUsed && mValues.size() != *expected && !mIsRepeatable &&\n                    !mDefaultValue.has_value()) {\n                    std::stringstream stream;\n                    stream << mUsedName << \": expected \" << *expected << \" argument(s). \"\n                           << mValues.size() << \" provided.\";\n                    throw std::runtime_error(stream.str());\n                } else {\n                    // TODO: check if an implicit value was programmed for this argument\n                    if (!mIsUsed && !mDefaultValue.has_value() && mIsRequired) {\n                        std::stringstream stream;\n                        stream << mNames[0] << \": required.\";\n                        throw std::runtime_error(stream.str());\n                    }\n                    if (mIsUsed && mIsRequired && mValues.size() == 0) {\n                        std::stringstream stream;\n                        stream << mUsedName << \": no value provided.\";\n                        throw std::runtime_error(stream.str());\n                    }\n                }\n            } else {\n                if (mValues.size() != expected && !mDefaultValue.has_value()) {\n                    std::stringstream stream;\n                    if (!mUsedName.empty())\n                        stream << mUsedName << \": \";\n                    stream << *expected << \" argument(s) expected. \" << mValues.size()\n                           << \" provided.\";\n                    throw std::runtime_error(stream.str());\n                }\n            }\n        }\n    }\n\n    auto maybe_nargs() const -> std::optional<std::size_t> {\n        if (mNumArgs < 0)\n            return std::nullopt;\n        else\n            return static_cast<std::size_t>(mNumArgs);\n    }\n\n    std::size_t get_arguments_length() const {\n        return std::accumulate(std::begin(mNames), std::end(mNames), std::size_t(0),\n                               [](const auto &sum, const auto &s) {\n                                   return sum + s.size() +\n                                          1; // +1 for space between names\n                               });\n    }\n\n    friend std::ostream &operator<<(std::ostream &stream,\n                                    const Argument &argument) {\n        std::stringstream nameStream;\n        std::copy(std::begin(argument.mNames), std::end(argument.mNames),\n                  std::ostream_iterator<std::string>(nameStream, \" \"));\n        stream << nameStream.str() << \"\\t\" << argument.mHelp;\n        if (argument.mDefaultValue.has_value()) {\n            if (!argument.mHelp.empty())\n                stream << \" \";\n            stream << \"[default: \" << argument.mDefaultValueRepr << \"]\";\n        } else if (argument.mIsRequired) {\n            if (!argument.mHelp.empty())\n                stream << \" \";\n            stream << \"[required]\";\n        }\n        stream << \"\\n\";\n        return stream;\n    }\n\n    template <typename T> bool operator!=(const T &aRhs) const {\n        return !(*this == aRhs);\n    }\n\n    /*\n     * Compare to an argument value of known type\n     * @throws std::logic_error in case of incompatible types\n     */\n    template <typename T> bool operator==(const T &aRhs) const {\n        if constexpr (!details::is_container_v<T>) {\n            return get<T>() == aRhs;\n        } else {\n            using ValueType = typename T::value_type;\n            auto tLhs = get<T>();\n            return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs),\n                              std::end(aRhs), [](const auto &lhs, const auto &rhs) {\n                    return std::any_cast<const ValueType &>(lhs) == rhs;\n                });\n        }\n    }\n\nprivate:\n    static constexpr int eof = std::char_traits<char>::eof();\n\n    static auto lookahead(std::string_view s) -> int {\n        if (s.empty())\n            return eof;\n        else\n            return static_cast<int>(static_cast<unsigned char>(s[0]));\n    }\n\n    /*\n     * decimal-literal:\n     *    '0'\n     *    nonzero-digit digit-sequence_opt\n     *    integer-part fractional-part\n     *    fractional-part\n     *    integer-part '.' exponent-part_opt\n     *    integer-part exponent-part\n     *\n     * integer-part:\n     *    digit-sequence\n     *\n     * fractional-part:\n     *    '.' post-decimal-point\n     *\n     * post-decimal-point:\n     *    digit-sequence exponent-part_opt\n     *\n     * exponent-part:\n     *    'e' post-e\n     *    'E' post-e\n     *\n     * post-e:\n     *    sign_opt digit-sequence\n     *\n     * sign: one of\n     *    '+' '-'\n     */\n    static bool is_decimal_literal(std::string_view s) {\n        auto is_digit = [](auto c) constexpr {\n            switch (c) {\n                case '0':\n                case '1':\n                case '2':\n                case '3':\n                case '4':\n                case '5':\n                case '6':\n                case '7':\n                case '8':\n                case '9':\n                    return true;\n                default:\n                    return false;\n            }\n        };\n\n        // precondition: we have consumed or will consume at least one digit\n        auto consume_digits = [=](std::string_view s) {\n            auto it = std::find_if_not(std::begin(s), std::end(s), is_digit);\n            return s.substr(it - std::begin(s));\n        };\n\n        switch (lookahead(s)) {\n            case '0': {\n                s.remove_prefix(1);\n                if (s.empty())\n                    return true;\n                else\n                    goto integer_part;\n            }\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9': {\n                s = consume_digits(s);\n                if (s.empty())\n                    return true;\n                else\n                    goto integer_part_consumed;\n            }\n            case '.': {\n                s.remove_prefix(1);\n                goto post_decimal_point;\n            }\n            default:\n                return false;\n        }\n\n        integer_part:\n        s = consume_digits(s);\n        integer_part_consumed:\n        switch (lookahead(s)) {\n            case '.': {\n                s.remove_prefix(1);\n                if (is_digit(lookahead(s)))\n                    goto post_decimal_point;\n                else\n                    goto exponent_part_opt;\n            }\n            case 'e':\n            case 'E': {\n                s.remove_prefix(1);\n                goto post_e;\n            }\n            default:\n                return false;\n        }\n\n        post_decimal_point:\n        if (is_digit(lookahead(s))) {\n            s = consume_digits(s);\n            goto exponent_part_opt;\n        } else {\n            return false;\n        }\n\n        exponent_part_opt:\n        switch (lookahead(s)) {\n            case eof:\n                return true;\n            case 'e':\n            case 'E': {\n                s.remove_prefix(1);\n                goto post_e;\n            }\n            default:\n                return false;\n        }\n\n        post_e:\n        switch (lookahead(s)) {\n            case '-':\n            case '+':\n                s.remove_prefix(1);\n        }\n        if (is_digit(lookahead(s))) {\n            s = consume_digits(s);\n            return s.empty();\n        } else {\n            return false;\n        }\n    }\n\n    static bool is_optional(std::string_view aName) {\n        return !is_positional(aName);\n    }\n\n    /*\n     * positional:\n     *    _empty_\n     *    '-'\n     *    '-' decimal-literal\n     *    !'-' anything\n     */\n    static bool is_positional(std::string_view aName) {\n        switch (lookahead(aName)) {\n            case eof:\n                return true;\n            case '-': {\n                aName.remove_prefix(1);\n                if (aName.empty())\n                    return true;\n                else\n                    return is_decimal_literal(aName);\n            }\n            default:\n                return true;\n        }\n    }\n\n    /*\n     * Get argument value given a type\n     * @throws std::logic_error in case of incompatible types\n     */\n    template <typename T> T get() const {\n        if (!mValues.empty()) {\n            if constexpr (details::is_container_v<T>)\n                return any_cast_container<T>(mValues);\n            else\n                return std::any_cast<T>(mValues.front());\n        }\n        if (mDefaultValue.has_value()) {\n            return std::any_cast<T>(mDefaultValue);\n        }\n        throw std::logic_error(\"No value provided for '\" + mNames.back() + \"'.\");\n    }\n\n    /*\n     * Get argument value given a type.\n     * @pre The object has no default value.\n     * @returns The stored value if any, std::nullopt otherwise.\n     */\n    template <typename T> auto present() const -> std::optional<T> {\n        if (mDefaultValue.has_value())\n            throw std::logic_error(\"Argument with default value always presents\");\n\n        if (mValues.empty())\n            return std::nullopt;\n        else if constexpr (details::is_container_v<T>)\n            return any_cast_container<T>(mValues);\n        else\n            return std::any_cast<T>(mValues.front());\n    }\n\n    template <typename T>\n    static auto any_cast_container(const std::vector<std::any> &aOperand) -> T {\n        using ValueType = typename T::value_type;\n\n        T tResult;\n        std::transform(\n            std::begin(aOperand), std::end(aOperand), std::back_inserter(tResult),\n            [](const auto &value) { return std::any_cast<ValueType>(value); });\n        return tResult;\n    }\n\n    std::vector<std::string> mNames;\n    std::string_view mUsedName;\n    std::string mHelp;\n    std::any mDefaultValue;\n    std::string mDefaultValueRepr;\n    std::any mImplicitValue;\n    using valued_action = std::function<std::any(const std::string &)>;\n    using void_action = std::function<void(const std::string &)>;\n    std::variant<valued_action, void_action> mAction{\n        std::in_place_type<valued_action>,\n        [](const std::string &aValue) { return aValue; }};\n    std::vector<std::any> mValues;\n    int mNumArgs = 1;\n    bool mIsOptional : true;\n    bool mIsRequired : true;\n    bool mIsRepeatable : true;\n    bool mIsUsed : true; // True if the optional argument is used by user\n};\n\nclass ArgumentParser {\npublic:\n    explicit ArgumentParser(std::string aProgramName = {},\n                            std::string aVersion = \"1.0\",\n                            default_arguments aArgs = default_arguments::all)\n        : mProgramName(std::move(aProgramName)), mVersion(std::move(aVersion)) {\n        if (aArgs & default_arguments::help) {\n            add_argument(\"-h\", \"--help\")\n                .action([&](const auto &) {\n                    std::cout << help().str();\n                    std::exit(0);\n                })\n                .default_value(false)\n                .help(\"shows help message and exits\")\n                .implicit_value(true)\n                .nargs(0);\n        }\n        if (aArgs & default_arguments::version) {\n            add_argument(\"-v\", \"--version\")\n                .action([&](const auto &) {\n                    std::cout << mVersion;\n                    std::exit(0);\n                })\n                .default_value(false)\n                .help(\"prints version information and exits\")\n                .implicit_value(true)\n                .nargs(0);\n        }\n    }\n\n    ArgumentParser(ArgumentParser &&) noexcept = default;\n    ArgumentParser &operator=(ArgumentParser &&) = default;\n\n    ArgumentParser(const ArgumentParser &other)\n        : mProgramName(other.mProgramName),\n          mVersion(other.mVersion),\n          mDescription(other.mDescription),\n          mEpilog(other.mEpilog),\n          mIsParsed(other.mIsParsed),\n          mPositionalArguments(other.mPositionalArguments),\n          mOptionalArguments(other.mOptionalArguments) {\n        for (auto it = std::begin(mPositionalArguments); it != std::end(mPositionalArguments);\n             ++it)\n            index_argument(it);\n        for (auto it = std::begin(mOptionalArguments); it != std::end(mOptionalArguments);\n             ++it)\n            index_argument(it);\n    }\n\n    ArgumentParser &operator=(const ArgumentParser &other) {\n        auto tmp = other;\n        std::swap(*this, tmp);\n        return *this;\n    }\n\n    // Parameter packing\n    // Call add_argument with variadic number of string arguments\n    template <typename... Targs> Argument &add_argument(Targs... Fargs) {\n        using array_of_sv = std::string_view[sizeof...(Targs)];\n        auto tArgument = mOptionalArguments.emplace(cend(mOptionalArguments),\n                                                    array_of_sv{Fargs...});\n\n        if (!tArgument->mIsOptional)\n            mPositionalArguments.splice(cend(mPositionalArguments),\n                                        mOptionalArguments, tArgument);\n\n        index_argument(tArgument);\n        return *tArgument;\n    }\n\n    // Parameter packed add_parents method\n    // Accepts a variadic number of ArgumentParser objects\n    template <typename... Targs>\n    ArgumentParser &add_parents(const Targs &... Fargs) {\n        for (const ArgumentParser &tParentParser : {std::ref(Fargs)...}) {\n            for (auto &tArgument : tParentParser.mPositionalArguments) {\n                auto it =\n                    mPositionalArguments.insert(cend(mPositionalArguments), tArgument);\n                index_argument(it);\n            }\n            for (auto &tArgument : tParentParser.mOptionalArguments) {\n                auto it =\n                    mOptionalArguments.insert(cend(mOptionalArguments), tArgument);\n                index_argument(it);\n            }\n        }\n        return *this;\n    }\n\n    ArgumentParser &add_description(std::string aDescription) {\n        mDescription = std::move(aDescription);\n        return *this;\n    }\n\n    ArgumentParser &add_epilog(std::string aEpilog) {\n        mEpilog = std::move(aEpilog);\n        return *this;\n    }\n\n    /* Call parse_args_internal - which does all the work\n     * Then, validate the parsed arguments\n     * This variant is used mainly for testing\n     * @throws std::runtime_error in case of any invalid argument\n     */\n    void parse_args(const std::vector<std::string> &aArguments) {\n        parse_args_internal(aArguments);\n        parse_args_validate();\n    }\n\n    /* Main entry point for parsing command-line arguments using this\n     * ArgumentParser\n     * @throws std::runtime_error in case of any invalid argument\n     */\n    void parse_args(int argc, const char *const argv[]) {\n        std::vector<std::string> arguments;\n        std::copy(argv, argv + argc, std::back_inserter(arguments));\n        parse_args(arguments);\n    }\n\n    /* Getter for options with default values.\n     * @throws std::logic_error if parse_args() has not been previously called\n     * @throws std::logic_error if there is no such option\n     * @throws std::logic_error if the option has no value\n     * @throws std::bad_any_cast if the option is not of type T\n     */\n    template <typename T = std::string>\n    T get(std::string_view aArgumentName) const {\n        if (!mIsParsed) {\n            throw std::logic_error(\"Nothing parsed, no arguments are available.\");\n        }\n        return (*this)[aArgumentName].get<T>();\n    }\n\n    /* Getter for options without default values.\n     * @pre The option has no default value.\n     * @throws std::logic_error if there is no such option\n     * @throws std::bad_any_cast if the option is not of type T\n     */\n    template <typename T = std::string>\n    auto present(std::string_view aArgumentName) const -> std::optional<T> {\n        return (*this)[aArgumentName].present<T>();\n    }\n\n    /* Getter that returns true for user-supplied options. Returns false if not\n     * user-supplied, even with a default value.\n     */\n    auto is_used(std::string_view aArgumentName) const {\n        return (*this)[aArgumentName].mIsUsed;\n    }\n\n    /* Indexing operator. Return a reference to an Argument object\n     * Used in conjuction with Argument.operator== e.g., parser[\"foo\"] == true\n     * @throws std::logic_error in case of an invalid argument name\n     */\n    Argument &operator[](std::string_view aArgumentName) const {\n        auto tIterator = mArgumentMap.find(aArgumentName);\n        if (tIterator != mArgumentMap.end()) {\n            return *(tIterator->second);\n        }\n        if (aArgumentName.front() != '-') {\n            std::string nameStr(aArgumentName);\n            // \"-\" + aArgumentName\n            nameStr = \"-\" + nameStr;\n            tIterator = mArgumentMap.find(nameStr);\n            if (tIterator != mArgumentMap.end()) {\n                return *(tIterator->second);\n            }\n            // \"--\" + aArgumentName\n            nameStr = \"-\" + nameStr;\n            tIterator = mArgumentMap.find(nameStr);\n            if (tIterator != mArgumentMap.end()) {\n                return *(tIterator->second);\n            }\n        }\n        throw std::logic_error(\"No such argument: \" + std::string(aArgumentName));\n    }\n\n    // Print help message\n    friend auto operator<<(std::ostream &stream, const ArgumentParser &parser)\n    -> std::ostream & {\n        stream.setf(std::ios_base::left);\n        stream << \"Usage: \" << parser.mProgramName << \" [options] \";\n        std::size_t tLongestArgumentLength = parser.get_length_of_longest_argument();\n\n        for (const auto &argument : parser.mPositionalArguments) {\n            stream << argument.mNames.front() << \" \";\n        }\n        stream << \"\\n\\n\";\n\n        if (!parser.mDescription.empty())\n            stream << parser.mDescription << \"\\n\\n\";\n\n        if (!parser.mPositionalArguments.empty())\n            stream << \"Positional arguments:\\n\";\n\n        for (const auto &mPositionalArgument : parser.mPositionalArguments) {\n            stream.width(tLongestArgumentLength);\n            stream << mPositionalArgument;\n        }\n\n        if (!parser.mOptionalArguments.empty())\n            stream << (parser.mPositionalArguments.empty() ? \"\" : \"\\n\")\n                   << \"Optional arguments:\\n\";\n\n        for (const auto &mOptionalArgument : parser.mOptionalArguments) {\n            stream.width(tLongestArgumentLength);\n            stream << mOptionalArgument;\n        }\n\n        if (!parser.mEpilog.empty())\n            stream << parser.mEpilog << \"\\n\\n\";\n\n        return stream;\n    }\n\n    // Format help message\n    auto help() const -> std::stringstream {\n        std::stringstream out;\n        out << *this;\n        return out;\n    }\n\n    // Printing the one and only help message\n    // I've stuck with a simple message format, nothing fancy.\n    [[deprecated(\"Use cout << program; instead.  See also help().\")]] std::string\n    print_help() const {\n        auto out = help();\n        std::cout << out.rdbuf();\n        return out.str();\n    }\n\nprivate:\n    /*\n     * @throws std::runtime_error in case of any invalid argument\n     */\n    void parse_args_internal(const std::vector<std::string> &aArguments) {\n        if (mProgramName.empty() && !aArguments.empty()) {\n            mProgramName = aArguments.front();\n        }\n        auto end = std::end(aArguments);\n        auto positionalArgumentIt = std::begin(mPositionalArguments);\n        for (auto it = std::next(std::begin(aArguments)); it != end;) {\n            const auto &tCurrentArgument = *it;\n            if (Argument::is_positional(tCurrentArgument)) {\n                if (positionalArgumentIt == std::end(mPositionalArguments)) {\n                    throw std::runtime_error(\n                        \"Maximum number of positional arguments exceeded\");\n                }\n                auto tArgument = positionalArgumentIt++;\n                it = tArgument->consume(it, end);\n                continue;\n            }\n\n            auto tIterator = mArgumentMap.find(tCurrentArgument);\n            if (tIterator != mArgumentMap.end()) {\n                auto tArgument = tIterator->second;\n                it = tArgument->consume(std::next(it), end, tIterator->first);\n            } else if (const auto &tCompoundArgument = tCurrentArgument;\n                tCompoundArgument.size() > 1 && tCompoundArgument[0] == '-' &&\n                tCompoundArgument[1] != '-') {\n                ++it;\n                for (std::size_t j = 1; j < tCompoundArgument.size(); j++) {\n                    auto tHypotheticalArgument = std::string{'-', tCompoundArgument[j]};\n                    auto tIterator2 = mArgumentMap.find(tHypotheticalArgument);\n                    if (tIterator2 != mArgumentMap.end()) {\n                        auto tArgument = tIterator2->second;\n                        it = tArgument->consume(it, end, tIterator2->first);\n                    } else {\n                        throw std::runtime_error(\"Unknown argument: \" + tCurrentArgument);\n                    }\n                }\n            } else {\n                throw std::runtime_error(\"Unknown argument: \" + tCurrentArgument);\n            }\n        }\n        mIsParsed = true;\n    }\n\n    /*\n     * @throws std::runtime_error in case of any invalid argument\n     */\n    void parse_args_validate() {\n        // Check if all arguments are parsed\n        std::for_each(std::begin(mArgumentMap), std::end(mArgumentMap),\n                      [](const auto &argPair) {\n                          const auto &tArgument = argPair.second;\n                          tArgument->validate();\n                      });\n    }\n\n    // Used by print_help.\n    std::size_t get_length_of_longest_argument() const {\n        if (mArgumentMap.empty())\n            return 0;\n        std::vector<std::size_t> argumentLengths(mArgumentMap.size());\n        std::transform(std::begin(mArgumentMap), std::end(mArgumentMap),\n                       std::begin(argumentLengths), [](const auto &argPair) {\n                const auto &tArgument = argPair.second;\n                return tArgument->get_arguments_length();\n            });\n        return *std::max_element(std::begin(argumentLengths),\n                                 std::end(argumentLengths));\n    }\n\n    using list_iterator = std::list<Argument>::iterator;\n\n    void index_argument(list_iterator argIt) {\n        for (auto &mName : std::as_const(argIt->mNames))\n            mArgumentMap.insert_or_assign(mName, argIt);\n    }\n\n    std::string mProgramName;\n    std::string mVersion;\n    std::string mDescription;\n    std::string mEpilog;\n    bool mIsParsed = false;\n    std::list<Argument> mPositionalArguments;\n    std::list<Argument> mOptionalArguments;\n    std::map<std::string_view, list_iterator, std::less<>> mArgumentMap;\n};\n\n} // namespace argparse"
  },
  {
    "path": "src/libs/util/include/util/enum.hpp",
    "content": "#pragma once\n\n\nnamespace Megaverse\n{\n\nenum class Status\n{\n    SUCCESS,\n    ERROR,\n};\n\n}"
  },
  {
    "path": "src/libs/util/include/util/filesystem_utils.hpp",
    "content": "#pragma once\n\n#include <string>\n#include <vector>\n#include <fstream>\n#include <sstream>\n\n\nnamespace Megaverse\n{\n\ninline char pathDelim()\n{\n#if defined(_WIN32)\n    return '\\\\';\n#else\n    return '/';\n#endif\n}\n\ntemplate<typename T>\nvoid pathJoinHelper(std::ostringstream &stream, const T &t)\n{\n    stream << t;\n}\n\ntemplate<typename T, typename... Args>\nvoid pathJoinHelper(std::ostringstream &stream, const T &t, Args... args)\n{\n    stream << t << pathDelim();\n    pathJoinHelper(stream, std::forward<Args>(args)...);\n}\n\ntemplate<typename... Args>\nstd::string pathJoin(Args... args)\n{\n    std::ostringstream stream;\n    pathJoinHelper(stream, std::forward<Args>(args)...);\n    return stream.str();\n}\n\n/// Returns number of bytes read.\nsize_t readAllBytes(const std::string &filename, std::vector<char> &buffer);\n\nsize_t readAllBytes(std::ifstream &stream, std::vector<char> &buffer);\n\n/// Actually checks if file is accessible.\nbool fileExists(const std::string &filename);\n\nstd::vector<std::string> listFilesInDirectory(const std::string &dir);\n\n}"
  },
  {
    "path": "src/libs/util/include/util/macro.hpp",
    "content": "#pragma once\n\n\n// compiler-dependent attributes\n#if defined(__clang__) || defined(__GNUG__)\n    #define FORCE_INLINE inline __attribute__((always_inline))\n#else\n    #define FORCE_INLINE __forceinline\n#endif\n\n\n#define EPSILON 1e-5f\n\n\n#define ARR_LENGTH(arr) sizeof(arr) / sizeof(arr[0])\n\n#define UNUSED(x) (void)(x)\n"
  },
  {
    "path": "src/libs/util/include/util/magnum.hpp",
    "content": "#pragma once\n\n#include <Magnum/Math/Vector.h>\n#include <Magnum/Math/Color.h>\n#include <Magnum/SceneGraph/SceneGraph.h>\n#include <Magnum/SceneGraph/MatrixTransformation3D.h>\n\n\nnamespace Megaverse\n{\n\nusing Object3D = Magnum::SceneGraph::Object<Magnum::SceneGraph::MatrixTransformation3D>;\nusing Scene3D = Magnum::SceneGraph::Scene<Magnum::SceneGraph::MatrixTransformation3D>;\n\nusing Radians = Magnum::Math::Rad<Magnum::Float>;\n\n\ntemplate<typename T>\nstd::ostream &operator<<(std::ostream &stream, const Magnum::Math::Vector3<T> &v)\n{\n    stream << v.x() << \" \" << v.y() << \" \" << v.z();\n    return stream;\n}\n\ninline Magnum::Color3 toRgbf(unsigned long long value)\n{\n    return Magnum::Math::unpack<Magnum::Color3>(\n        Magnum::Math::Color3<Magnum::UnsignedByte>{\n            Magnum::UnsignedByte(value >> 16), Magnum::UnsignedByte(value >> 8), Magnum::UnsignedByte(value)\n        }\n    );\n}\n\ninline Magnum::Math::Deg<Magnum::Float> degrees(double value) { return Magnum::Math::Deg<Magnum::Float>(Magnum::Float(value)); }\n\n}\n\nnamespace Magnum::Math\n{\n\ntemplate<std::size_t size, class T> inline Vector<size, int> lround(const Vector<size, T>& a)\n{\n    Vector<size, int> out{Magnum::NoInit};\n    for(std::size_t i = 0; i != size; ++i)\n        out[i] = std::lround(a[i]);\n    return out;\n}\n\ntemplate<typename CONTAINER_T>\nstd::vector<Magnum::Vector3> toFloat(const CONTAINER_T &vectors)\n{\n    std::vector<Magnum::Vector3> result;\n    result.reserve(vectors.size());\n\n    for (const auto &v : vectors)\n        result.emplace_back(v);\n\n    return result;\n}\n\n}"
  },
  {
    "path": "src/libs/util/include/util/math_utils.hpp",
    "content": "#pragma once\n\n\nnamespace Megaverse\n{\n\ntemplate<typename T> T triangularNumber(T n)\n{\n    return n * (n + 1) / 2;\n}\n\n}"
  },
  {
    "path": "src/libs/util/include/util/os_utils.hpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <unistd.h>\n\n\n/**\n * https://gist.github.com/thirdwing/da4621eb163a886a03c5\n * @param vm_usage Virtual memory size in bytes\n * @param resident_set Resident Set Size: number of pages the process has in real memory (in bytes)\n */\ninline void unixProcessMemUsage(double& vm_usage, double& resident_set)\n{\n    vm_usage     = 0.0;\n    resident_set = 0.0;\n\n    // the two fields we want\n    unsigned long vsize;\n    long rss;\n    {\n        std::string ignore;\n        std::ifstream ifs(\"/proc/self/stat\", std::ios_base::in);\n        ifs >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore\n            >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore\n            >> ignore >> ignore >> vsize >> rss;\n    }\n\n    static long page_size_bytes = sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages\n    vm_usage = double(vsize);\n    resident_set = double(rss) * double(page_size_bytes);\n}\n"
  },
  {
    "path": "src/libs/util/include/util/perlin_noise.hpp",
    "content": "//----------------------------------------------------------------------------------------\n//\n//\tsiv::PerlinNoise\n//\tPerlin noise library for modern C++\n//\n//\tCopyright (C) 2013-2020 Ryo Suzuki <reputeless@gmail.com>\n//\n//\tPermission is hereby granted, free of charge, to any person obtaining a copy\n//\tof this software and associated documentation files(the \"Software\"), to deal\n//\tin the Software without restriction, including without limitation the rights\n//\tto use, copy, modify, merge, publish, distribute, sublicense, and / or sell\n//\tcopies of the Software, and to permit persons to whom the Software is\n//\tfurnished to do so, subject to the following conditions :\n//\t\n//\tThe above copyright notice and this permission notice shall be included in\n//\tall copies or substantial portions of the Software.\n//\t\n//\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE\n//\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//\tTHE SOFTWARE.\n//\n//----------------------------------------------------------------------------------------\n\n# pragma once\n# include <cstdint>\n# include <algorithm>\n# include <array>\n# ifdef __cpp_concepts\n# if __has_include(<concepts>)\n# include <concepts>\n# endif\n# endif\n# include <iterator>\n# include <numeric>\n# include <random>\n# include <type_traits>\n\nnamespace siv\n{\n# ifdef __cpp_lib_concepts\n\ttemplate <std::floating_point Float>\n# else\n\ttemplate <class Float>\n# endif\n\tclass BasicPerlinNoise\n\t{\n\tpublic:\n\n\t\tusing value_type = Float;\n\n\tprivate:\n\n\t\tstd::uint8_t p[512];\n\n\t\t[[nodiscard]]\n\t\tstatic constexpr value_type Fade(value_type t) noexcept\n\t\t{\n\t\t\treturn t * t * t * (t * (t * 6 - 15) + 10);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tstatic constexpr value_type Lerp(value_type t, value_type a, value_type b) noexcept\n\t\t{\n\t\t\treturn a + t * (b - a);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tstatic constexpr value_type Grad(std::uint8_t hash, value_type x, value_type y, value_type z) noexcept\n\t\t{\n\t\t\tconst std::uint8_t h = hash & 15;\n\t\t\tconst value_type u = h < 8 ? x : y;\n\t\t\tconst value_type v = h < 4 ? y : h == 12 || h == 14 ? x : z;\n\t\t\treturn ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tstatic constexpr value_type Weight(std::int32_t octaves) noexcept\n\t\t{\n\t\t\tvalue_type amp = 1;\n\t\t\tvalue_type value = 0;\n\n\t\t\tfor (std::int32_t i = 0; i < octaves; ++i)\n\t\t\t{\n\t\t\t\tvalue += amp;\n\t\t\t\tamp /= 2;\n\t\t\t}\n\n\t\t\treturn value;\n\t\t}\n\n\tpublic:\n\n\t# if __has_cpp_attribute(nodiscard) >= 201907L\n\t\t[[nodiscard]]\n\t# endif\n\t\texplicit BasicPerlinNoise(std::uint32_t seed = std::default_random_engine::default_seed)\n\t\t{\n\t\t\treseed(seed);\n\t\t}\n\n\t# ifdef __cpp_lib_concepts\n\t\ttemplate <std::uniform_random_bit_generator URNG>\n\t# else\n\t\ttemplate <class URNG, std::enable_if_t<!std::is_arithmetic_v<URNG>>* = nullptr>\n\t# endif\n\t# if __has_cpp_attribute(nodiscard) >= 201907L\n\t\t[[nodiscard]]\n\t# endif\n\t\texplicit BasicPerlinNoise(URNG&& urng)\n\t\t{\n\t\t\treseed(std::forward<URNG>(urng));\n\t\t}\n\n\t\tvoid reseed(std::uint32_t seed)\n\t\t{\n\t\t\tfor (size_t i = 0; i < 256; ++i)\n\t\t\t{\n\t\t\t\tp[i] = static_cast<std::uint8_t>(i);\n\t\t\t}\n\n\t\t\tstd::shuffle(std::begin(p), std::begin(p) + 256, std::default_random_engine(seed));\n\n\t\t\tfor (size_t i = 0; i < 256; ++i)\n\t\t\t{\n\t\t\t\tp[256 + i] = p[i];\n\t\t\t}\n\t\t}\n\n\t# ifdef __cpp_lib_concepts\n\t\ttemplate <std::uniform_random_bit_generator URNG>\n\t# else\n\t\ttemplate <class URNG, std::enable_if_t<!std::is_arithmetic_v<URNG>>* = nullptr>\n\t# endif\n\t\tvoid reseed(URNG&& urng)\n\t\t{\n\t\t\tfor (size_t i = 0; i < 256; ++i)\n\t\t\t{\n\t\t\t\tp[i] = static_cast<std::uint8_t>(i);\n\t\t\t}\n\n\t\t\tstd::shuffle(std::begin(p), std::begin(p) + 256, std::forward<URNG>(urng));\n\n\t\t\tfor (size_t i = 0; i < 256; ++i)\n\t\t\t{\n\t\t\t\tp[256 + i] = p[i];\n\t\t\t}\n\t\t}\n\n\t\t///////////////////////////////////////\n\t\t//\n\t\t//\tNoise [-1, 1]\n\t\t//\n\t\t[[nodiscard]]\n\t\tvalue_type noise1D(value_type x) const noexcept\n\t\t{\n\t\t\treturn noise3D(x, 0, 0);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type noise2D(value_type x, value_type y) const noexcept\n\t\t{\n\t\t\treturn noise3D(x, y, 0);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type noise3D(value_type x, value_type y, value_type z) const noexcept\n\t\t{\n\t\t\tconst std::int32_t X = static_cast<std::int32_t>(std::floor(x)) & 255;\n\t\t\tconst std::int32_t Y = static_cast<std::int32_t>(std::floor(y)) & 255;\n\t\t\tconst std::int32_t Z = static_cast<std::int32_t>(std::floor(z)) & 255;\n\n\t\t\tx -= std::floor(x);\n\t\t\ty -= std::floor(y);\n\t\t\tz -= std::floor(z);\n\n\t\t\tconst value_type u = Fade(x);\n\t\t\tconst value_type v = Fade(y);\n\t\t\tconst value_type w = Fade(z);\n\n\t\t\tconst std::int32_t A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;\n\t\t\tconst std::int32_t B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;\n\n\t\t\treturn Lerp(w, Lerp(v, Lerp(u, Grad(p[AA], x, y, z),\n\t\t\t\tGrad(p[BA], x - 1, y, z)),\n\t\t\t\tLerp(u, Grad(p[AB], x, y - 1, z),\n\t\t\t\tGrad(p[BB], x - 1, y - 1, z))),\n\t\t\t\tLerp(v, Lerp(u, Grad(p[AA + 1], x, y, z - 1),\n\t\t\t\tGrad(p[BA + 1], x - 1, y, z - 1)),\n\t\t\t\tLerp(u, Grad(p[AB + 1], x, y - 1, z - 1),\n\t\t\t\tGrad(p[BB + 1], x - 1, y - 1, z - 1))));\n\t\t}\n\n\t\t///////////////////////////////////////\n\t\t//\n\t\t//\tNoise [0, 1]\n\t\t//\n\t\t[[nodiscard]]\n\t\tvalue_type noise1D_0_1(value_type x) const noexcept\n\t\t{\n\t\t\treturn noise1D(x)\n\t\t\t\t* value_type(0.5) + value_type(0.5);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type noise2D_0_1(value_type x, value_type y) const noexcept\n\t\t{\n\t\t\treturn noise2D(x, y)\n\t\t\t\t* value_type(0.5) + value_type(0.5);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type noise3D_0_1(value_type x, value_type y, value_type z) const noexcept\n\t\t{\n\t\t\treturn noise3D(x, y, z)\n\t\t\t\t* value_type(0.5) + value_type(0.5);\n\t\t}\n\n\t\t///////////////////////////////////////\n\t\t//\n\t\t//\tAccumulated octave noise\n\t\t//\t* Return value can be outside the range [-1, 1]\n\t\t//\n\t\t[[nodiscard]]\n\t\tvalue_type accumulatedOctaveNoise1D(value_type x, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\tvalue_type result = 0;\n\t\t\tvalue_type amp = 1;\n\n\t\t\tfor (std::int32_t i = 0; i < octaves; ++i)\n\t\t\t{\n\t\t\t\tresult += noise1D(x) * amp;\n\t\t\t\tx *= 2;\n\t\t\t\tamp /= 2;\n\t\t\t}\n\n\t\t\treturn result; // unnormalized\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type accumulatedOctaveNoise2D(value_type x, value_type y, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\tvalue_type result = 0;\n\t\t\tvalue_type amp = 1;\n\n\t\t\tfor (std::int32_t i = 0; i < octaves; ++i)\n\t\t\t{\n\t\t\t\tresult += noise2D(x, y) * amp;\n\t\t\t\tx *= 2;\n\t\t\t\ty *= 2;\n\t\t\t\tamp /= 2;\n\t\t\t}\n\n\t\t\treturn result; // unnormalized\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type accumulatedOctaveNoise3D(value_type x, value_type y, value_type z, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\tvalue_type result = 0;\n\t\t\tvalue_type amp = 1;\n\n\t\t\tfor (std::int32_t i = 0; i < octaves; ++i)\n\t\t\t{\n\t\t\t\tresult += noise3D(x, y, z) * amp;\n\t\t\t\tx *= 2;\n\t\t\t\ty *= 2;\n\t\t\t\tz *= 2;\n\t\t\t\tamp /= 2;\n\t\t\t}\n\n\t\t\treturn result; // unnormalized\n\t\t}\n\n\t\t///////////////////////////////////////\n\t\t//\n\t\t//\tNormalized octave noise [-1, 1]\n\t\t//\n\t\t[[nodiscard]]\n\t\tvalue_type normalizedOctaveNoise1D(value_type x, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn accumulatedOctaveNoise1D(x, octaves)\n\t\t\t\t/ Weight(octaves);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type normalizedOctaveNoise2D(value_type x, value_type y, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn accumulatedOctaveNoise2D(x, y, octaves)\n\t\t\t\t/ Weight(octaves);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type normalizedOctaveNoise3D(value_type x, value_type y, value_type z, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn accumulatedOctaveNoise3D(x, y, z, octaves)\n\t\t\t\t/ Weight(octaves);\n\t\t}\n\n\t\t///////////////////////////////////////\n\t\t//\n\t\t//\tAccumulated octave noise clamped within the range [0, 1]\n\t\t//\n\t\t[[nodiscard]]\n\t\tvalue_type accumulatedOctaveNoise1D_0_1(value_type x, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn std::clamp<value_type>(accumulatedOctaveNoise1D(x, octaves)\n\t\t\t\t* value_type(0.5) + value_type(0.5), 0, 1);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type accumulatedOctaveNoise2D_0_1(value_type x, value_type y, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn std::clamp<value_type>(accumulatedOctaveNoise2D(x, y, octaves)\n\t\t\t\t* value_type(0.5) + value_type(0.5), 0, 1);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type accumulatedOctaveNoise3D_0_1(value_type x, value_type y, value_type z, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn std::clamp<value_type>(accumulatedOctaveNoise3D(x, y, z, octaves)\n\t\t\t\t* value_type(0.5) + value_type(0.5), 0, 1);\n\t\t}\n\n\t\t///////////////////////////////////////\n\t\t//\n\t\t//\tNormalized octave noise [0, 1]\n\t\t//\n\t\t[[nodiscard]]\n\t\tvalue_type normalizedOctaveNoise1D_0_1(value_type x, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn normalizedOctaveNoise1D(x, octaves)\n\t\t\t\t* value_type(0.5) + value_type(0.5);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type normalizedOctaveNoise2D_0_1(value_type x, value_type y, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn normalizedOctaveNoise2D(x, y, octaves)\n\t\t\t\t* value_type(0.5) + value_type(0.5);\n\t\t}\n\n\t\t[[nodiscard]]\n\t\tvalue_type normalizedOctaveNoise3D_0_1(value_type x, value_type y, value_type z, std::int32_t octaves) const noexcept\n\t\t{\n\t\t\treturn normalizedOctaveNoise3D(x, y, z, octaves)\n\t\t\t\t* value_type(0.5) + value_type(0.5);\n\t\t}\n\n\t\t///////////////////////////////////////\n\t\t//\n\t\t//\tSerialization\n\t\t//\n\t\tvoid serialize(std::array<std::uint8_t, 256>& s) const noexcept\n\t\t{\n\t\t\tfor (std::size_t i = 0; i < 256; ++i)\n\t\t\t{\n\t\t\t\ts[i] = p[i];\n\t\t\t}\n\t\t}\n\n\t\tvoid deserialize(const std::array<std::uint8_t, 256>& s) noexcept\n\t\t{\n\t\t\tfor (std::size_t i = 0; i < 256; ++i)\n\t\t\t{\n\t\t\t\tp[256 + i] = p[i] = s[i];\n\t\t\t}\n\t\t}\n\n\t\t///////////////////////////////////////\n\t\t//\n\t\t//\tLegacy interface\n\t\t//\n\t\t[[deprecated(\"use noise1D() instead\")]]\n\t\tdouble noise(double x) const;\n\t\t[[deprecated(\"use noise2D() instead\")]]\n\t\tdouble noise(double x, double y) const;\n\t\t[[deprecated(\"use noise3D() instead\")]]\n\t\tdouble noise(double x, double y, double z) const;\n\n\t\t[[deprecated(\"use noise1D_0_1() instead\")]]\n\t\tdouble noise0_1(double x) const;\n\t\t[[deprecated(\"use noise2D_0_1() instead\")]]\n\t\tdouble noise0_1(double x, double y) const;\n\t\t[[deprecated(\"use noise3D_0_1() instead\")]]\n\t\tdouble noise0_1(double x, double y, double z) const;\n\n\t\t[[deprecated(\"use accumulatedOctaveNoise1D() instead\")]]\n\t\tdouble octaveNoise(double x, std::int32_t octaves) const;\n\t\t[[deprecated(\"use accumulatedOctaveNoise2D() instead\")]]\n\t\tdouble octaveNoise(double x, double y, std::int32_t octaves) const;\n\t\t[[deprecated(\"use accumulatedOctaveNoise3D() instead\")]]\n\t\tdouble octaveNoise(double x, double y, double z, std::int32_t octaves) const;\n\n\t\t[[deprecated(\"use accumulatedOctaveNoise1D_0_1() instead\")]]\n\t\tdouble octaveNoise0_1(double x, std::int32_t octaves) const;\n\t\t[[deprecated(\"use accumulatedOctaveNoise2D_0_1() instead\")]]\n\t\tdouble octaveNoise0_1(double x, double y, std::int32_t octaves) const;\n\t\t[[deprecated(\"use accumulatedOctaveNoise3D_0_1() instead\")]]\n\t\tdouble octaveNoise0_1(double x, double y, double z, std::int32_t octaves) const;\n\t};\n\n\tusing PerlinNoise = BasicPerlinNoise<double>;\n}\n"
  },
  {
    "path": "src/libs/util/include/util/string_utils.hpp",
    "content": "#pragma once\n\n#include <string>\n#include <vector>\n#include <sstream>\n\n\nnamespace Megaverse\n{\n\nstd::vector<std::string> splitString(const std::string &s, const std::string &d);\n\nbool startsWith(const std::string &s, const std::string &t);\n\nbool endsWith(const std::string &s, const std::string &t);\n\nstd::string toLower(const std::string &s);\n\ntemplate<typename T>\nT stringTo(const std::string &s, bool &ok)\n{\n    T val;\n    // slow but easy to write\n    if (std::istringstream(s) >> val) {\n        ok = true;\n        return val;\n    }\n\n    ok = false;\n    return T();\n}\n\n}"
  },
  {
    "path": "src/libs/util/include/util/tiny_logger.hpp",
    "content": "#pragma once\n\n#include <memory>\n#include <vector>\n#include <ostream>\n#include <sstream>\n#include <iostream>\n\n\nnamespace Megaverse\n{\n\nenum LogLevel\n{\n    FATAL,\n    ERROR,\n    WARNING,\n    INFO,\n    VERBOSE,\n    DEBUG,\n};\n\n\nvoid setLogLevel(LogLevel level);\n\n\nclass LogMessage\n{\npublic:\n    LogMessage(LogLevel level, const char *file, int line, const char *func, std::ostream *outStream = &std::cout);\n\n    ~LogMessage();\n\n    std::ostringstream &operator()();\n\nprivate:\n    std::shared_ptr<std::ostringstream> stream;\n    std::ostream *outStream;\n    LogLevel level;\n};\n\nclass NullStream : public std::ostringstream\n{\npublic:\n    NullStream()\n        : std::ostringstream() {}\n\n    NullStream &operator()()\n    {\n        return *this;\n    }\n};\n\ntemplate<typename T>\ninline NullStream &operator<<(NullStream &stream, T &&)\n{\n    return stream;\n}\n\n\n// helper macros\n\n#define TLOG(level) LogMessage(level, __FILE__, __LINE__, __FUNCTION__)()\n\n#define TLOG_IF(level, cond) !(cond) ? NullStream()() : TLOG(level)\n\n// die if condition is not true\n#define TCHECK(cond) TLOG_IF(FATAL, !(cond))\n\n\n// various helper functions\n\ntemplate<typename T>\nstd::ostream &operator<<(std::ostream &stream, const std::vector<T> &vec)\n{\n    stream << '[';\n    const auto end = std::end(vec);\n    for (auto it = std::begin(vec); it != end; ++it) {\n        stream << *it;\n        if (it + 1 != end)\n            stream << \", \";\n    }\n    stream << ']';\n    return stream;\n}\n\n}"
  },
  {
    "path": "src/libs/util/include/util/tiny_profiler.hpp",
    "content": "#pragma once\n\n#include <memory>\n\n\nnamespace Megaverse\n{\n\nclass TinyProfiler\n{\n    /// Private implementation to hide some stl headers.\n    struct TinyProfilerImpl;\n\npublic:\n    /// Singleton.\n    static TinyProfiler &instance();\n\n    /// Start measurement for key.\n    void startTimer(const std::string &key);\n\n    /// Stop time measurement, but keep time measured so far.\n    void pauseTimer(const std::string &key);\n\n    /// Read total measured time since start.\n    float readTimer(const std::string &key, bool log = false);\n\n    /// Stop measurement for key, returns all measured time since start.\n    float stopTimer(const std::string &key, bool log = false);\n\n    TinyProfiler(const TinyProfiler &) = delete;\n\n    void operator=(const TinyProfiler &) = delete;\n\nprivate:\n    TinyProfiler();\n\nprivate:\n    std::unique_ptr<TinyProfilerImpl> data;\n};\n\nTinyProfiler &tprof();\n\n}"
  },
  {
    "path": "src/libs/util/include/util/util.hpp",
    "content": "#pragma once\n\n#include <random>\n#include <cstdint>\n#include <algorithm>\n\n#include <util/macro.hpp>\n\n\nnamespace Megaverse\n{\n\ntemplate<typename T>\nint sgn(T val)\n{\n    return (T(0) < val) - (val < T(0));\n}\n\ntemplate<typename T>\nFORCE_INLINE T sqr(T x)\n{\n    return x * x;\n}\n\nusing Rng = std::mt19937;\n\n/**\n * @return random integer from [low, high).\n */\ninline int randRange(int low, int high, Rng &rng)\n{\n    return std::uniform_int_distribution<>{low, high - 1}(rng);\n}\n\n/**\n * @return random boolean.\n */\ninline bool randomBool(Rng &rng)\n{\n    return bool(randRange(0, 2, rng));\n}\n\n/**\n * @return random number in [0, 1)\n */\ninline float frand(Rng &rng)\n{\n    return std::uniform_real_distribution<float>{0, 1}(rng);\n}\n\ntemplate<typename CONTAINER_T>\nauto randomSample(const CONTAINER_T &container, Rng &rng)\n{\n    const auto idx = randRange(0, container.size(), rng);\n    return container[idx];\n}\n\ntemplate<typename T>\nvoid endianSwap(T *x)\n{\n    int size = sizeof(*x);\n\n    std::reverse(static_cast<uint8_t *>(x), static_cast<uint8_t *>(x + size));\n}\n\ntemplate<typename C, typename T>\nbool contains(const C &c, const T &val)\n{\n    return std::find(std::begin(c), std::end(c), val) != std::end(c);\n}\n\nvoid memcpyStride(char *dst, const char *src, int elemSize, int numElements, int ofs, int stride);\n\n}"
  },
  {
    "path": "src/libs/util/include/util/voxel_grid.hpp",
    "content": "#pragma once\n\n#include <unordered_map>\n\n#include <Magnum/Magnum.h>\n#include <Magnum/Math/Vector3.h>\n\n#include <util/magnum.hpp>\n\n\nnamespace Megaverse\n{\n\nusing VoxelCoords = Magnum::Vector3i;\n\nconstexpr int maxGridResolution = 1'024, logMaxGridResolution = 10, maxAbsVoxelCoord = maxGridResolution / 2;\n\ninline VoxelCoords toVoxel(const Magnum::Vector3 &v)\n{\n    return lround(floor(v));\n}\n\ninline int manhattanDistance(const VoxelCoords &a, const VoxelCoords &b)\n{\n    const auto delta = a - b;\n    return std::abs(delta.x()) + std::abs(delta.y()) + std::abs(delta.z());\n}\n\n}\n\n//bool operator==(const VoxelCoords &lhs, const VoxelCoords &rhs)\n//{\n//    return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();\n//}\n\nnamespace std\n{\n\ntemplate <> struct hash<Megaverse::VoxelCoords>\n{\n    std::size_t operator()(const Megaverse::VoxelCoords &voxel) const noexcept\n    {\n        constexpr auto shift = Megaverse::logMaxGridResolution;\n        constexpr auto offset = Megaverse::maxAbsVoxelCoord;\n        const int x = voxel.x() + offset, y = voxel.y() + offset, z = voxel.z() + offset;\n\n        return size_t((x << (2 * shift)) + (y << shift) + z);\n    }\n};\n\n}\n\n\nnamespace Megaverse\n{\n\ntemplate<typename VoxelState> class VoxelGrid\n{\npublic:\n    using HashMap = std::unordered_map<VoxelCoords, VoxelState>;\n\npublic:\n    /**\n     * Ctor.\n     * @param voxelCount number of voxels to reserve initially.\n     * @param origin point with the lowest coords covered by the voxelGrid. Corresponds to voxel {0, 0, 0}.\n     * @param voxelSize scale of one voxel\n     */\n    explicit VoxelGrid(size_t voxelCount, const Magnum::Vector3 &origin, float voxelSize)\n    : voxelCount{voxelCount}\n    , grid{voxelCount}\n    , origin{origin}\n    , voxelSize{voxelSize} {}\n\n    /**\n     * Reset the grid (empty).\n     */\n    void clear()\n    {\n        grid = HashMap{voxelCount};\n    }\n\n    /**\n     * @param coords coordinates of a voxel.\n     * @return check whether voxel at these coordinates is present in the map.\n     */\n    bool hasVoxel(const VoxelCoords &coords) const\n    {\n        return bool(grid.count(coords));\n    }\n\n    /**\n     * @param coords location in voxel grid.\n     * @return pointer to VoxelState at the \"coords\" location, or nullptr if nothing is there.\n     */\n    const VoxelState * get(const VoxelCoords &coords) const\n    {\n        auto voxelIt = grid.find(coords);\n        if (voxelIt == grid.end())\n            return nullptr;\n\n        return &(voxelIt->second);\n    }\n\n    VoxelState * get(const VoxelCoords &coords)\n    {\n        auto voxelIt = grid.find(coords);\n        if (voxelIt == grid.end())\n            return nullptr;\n\n        return &(voxelIt->second);\n    }\n\n    const VoxelState * getWithVector(const Magnum::Vector3 &v) const\n    {\n        return get(getCoords(v));\n    }\n\n    VoxelState * getWithVector(const Magnum::Vector3 &v)\n    {\n        return get(getCoords(v));\n    }\n\n    /**\n     * Override the voxel state in the particular voxel.\n     * @param coords\n     * @param state\n     */\n    void set(const VoxelCoords &coords, const VoxelState &state)\n    {\n        grid[coords] = state;\n    }\n\n    void remove(const VoxelCoords &coords)\n    {\n        grid.erase(coords);\n    }\n\n    /**\n     * Convert floating point coordinates of a point in space to voxel coordinates.\n     * @param v point (vector) in 3D space.\n     * @return corresponding voxel coords.\n     */\n    VoxelCoords getCoords(const Magnum::Vector3 &v) const\n    {\n        const auto coordsFloat = (v - origin) / voxelSize;\n        const auto coords = toVoxel(coordsFloat);\n        return coords;\n    }\n\n    const HashMap & getHashMap() const\n    {\n        return grid;\n    }\n\n    float getVoxelSize() const { return voxelSize; }\n\nprivate:\n    size_t voxelCount;\n\n    HashMap grid;\n\n    Magnum::Vector3 origin;\n    float voxelSize;\n};\n\n}"
  },
  {
    "path": "src/libs/util/src/filesystem_utils.cpp",
    "content": "#include <util/filesystem_utils.hpp>\n\nnamespace Megaverse\n{\n\nsize_t readAllBytes(const std::string &filename, std::vector<char> &buffer)\n{\n    std::ifstream f{filename, std::ios::in | std::ios::binary};\n    return readAllBytes(f, buffer);\n}\n\nsize_t readAllBytes(std::ifstream &stream, std::vector<char> &buffer)\n{\n    stream.seekg(0, std::ios::end);\n    const auto size = stream.tellg();\n    stream.seekg(0);\n    buffer.resize(size);\n    if (stream.read(buffer.data(), size))\n        return size;\n    else\n        return 0;\n}\n\nbool fileExists(const std::string& filename)\n{\n    std::ifstream f(filename);\n    return f.good();\n}\n\n// This crashes on GCC 8.4 due to some obscure linking error (let's just wait for a new compiler I guess lol)\n//std::vector<std::string> listFilesInDirectory(const std::string &dir)\n//{\n//    std::vector<std::string> result;\n//\n//    for (const auto & entry : fs::directory_iterator(dir))\n//        result.emplace_back(entry.path().string());\n//\n//    return result;\n//}\n\n}"
  },
  {
    "path": "src/libs/util/src/string_utils.cpp",
    "content": "#include <cstring>\n#include <algorithm>\n\n#include <util/string_utils.hpp>\n\n\nnamespace Megaverse\n{\n\nstd::vector<std::string> splitString(const std::string &s, const std::string &d)\n{\n    std::vector<std::string> result;\n\n    char *cStr = new char[s.size() + 1];\n    strcpy(cStr, s.c_str());\n    char *strtokPtr = nullptr;\n    char *token = strtok_r(cStr, d.c_str(), &strtokPtr);\n    while (token) {\n        result.emplace_back(token);\n        token = strtok_r(nullptr, d.c_str(), &strtokPtr);\n    }\n\n    delete[] cStr;\n    return result;\n}\n\nbool startsWith(const std::string &s, const std::string &t)\n{\n    if (t.empty())\n        return true;\n    return s.find(t) == 0;\n}\n\nbool endsWith(const std::string &s, const std::string &t)\n{\n    if (t.size() > s.size())\n        return false;\n    if (t.empty())\n        return true;\n    return s.find(t) == s.size() - t.size();\n}\n\nstd::string toLower(const std::string &input)\n{\n    auto s = input;\n    std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::tolower(c); });\n    return s;\n}\n\n}"
  },
  {
    "path": "src/libs/util/src/tiny_logger.cpp",
    "content": "#include <mutex>\n#include <thread>\n#include <cstring>\n#include <iomanip>\n\n#include <util/tiny_logger.hpp>\n#include <util/filesystem_utils.hpp>\n\n\nusing namespace std::chrono;\nusing namespace std::chrono_literals;\n\nusing namespace Megaverse;\n\n\nnamespace\n{\n\n/// Everything with level higher than logLevel will be discarded.\nLogLevel logLevel = DEBUG;\n\n\nconst char *levelToStr(LogLevel level)\n{\n    switch (level) {\n        case FATAL:\n            return \"FAT\";\n        case ERROR:\n            return \"ERR\";\n        case WARNING:\n            return \"WRN\";\n        case INFO:\n            return \"INF\";\n        case VERBOSE:\n            return \"VER\";\n        case DEBUG:\n            return \"DBG\";\n        default:\n            return \"\";\n    }\n}\n\nconst char *constBasename(const char *filepath)\n{\n    const char *basename = strrchr(filepath, pathDelim());\n    return basename ? basename + 1 : filepath;\n}\n\nvoid printTime(std::ostream &stream)\n{\n    char timeStr[1 << 6];\n    const system_clock::time_point now = system_clock::now();\n    const time_t timestamp = system_clock::to_time_t(now);\n    strftime(timeStr, sizeof(timeStr), \"%m-%d %T\", std::localtime(&timestamp));\n\n    const auto sinceEpoch = now.time_since_epoch();\n    const system_clock::duration fraction = sinceEpoch - duration_cast<seconds>(sinceEpoch);\n    const long long ms = duration_cast<milliseconds>(fraction).count();\n\n    stream << timeStr << '.' << std::setw(3) << std::setfill('0') << ms << ' ';\n}\n\n}\n\n\nnamespace Megaverse\n{\n\nvoid setLogLevel(LogLevel level)\n{\n    logLevel = level;\n}\n\nLogMessage::LogMessage(LogLevel lvl, const char *file, int line, const char *func, std::ostream *outStream)\n    : stream{nullptr}\n    , outStream{outStream}\n    , level{lvl}\n{\n    if (level > logLevel) {\n        static std::shared_ptr<std::ostringstream> nullStream = std::make_shared<NullStream>();\n        stream = nullStream;\n    } else {\n        stream = std::make_shared<std::ostringstream>();\n\n        *stream << \"[\";\n        printTime(*stream);\n\n        *stream << levelToStr(level) << ' ' << constBasename(file) << ':' << line;\n        if (func) {\n            *stream << ' ' << func;\n            if (!strchr(func, '('))\n                *stream << \"()\";\n        }\n        *stream << \"] \";\n    }\n}\n\nLogMessage::~LogMessage()\n{\n    if (stream)\n        *stream << '\\n';\n\n    if (level <= logLevel) {\n        static std::mutex mutex;\n        std::lock_guard<std::mutex> lock(mutex);\n        *outStream << stream->str();\n    }\n\n    if (level == FATAL) {\n        *outStream << \"\\nExiting due to FATAL error, see the logs for details...\\n\\n\\n\";\n        std::this_thread::sleep_for(2s);\n        exit(-1);\n    }\n}\n\nstd::ostringstream &LogMessage::operator()()\n{\n    return *stream;\n}\n\n}"
  },
  {
    "path": "src/libs/util/src/tiny_profiler.cpp",
    "content": "#include <memory>\n\n#include <map>\n#include <mutex>\n#include <string>\n#include <chrono>\n\n#include <util/tiny_logger.hpp>\n#include <util/tiny_profiler.hpp>\n\n\nusing std::chrono::high_resolution_clock;\nusing std::chrono::duration;\nusing std::chrono::duration_cast;\nusing std::chrono::microseconds;\nusing std::chrono::milliseconds;\n\nusing namespace Megaverse;\n\n\nnamespace\n{\n\n// types\ntypedef high_resolution_clock::time_point tstamp;\n\n// helper functions\ninline microseconds::rep passedSince(const tstamp &tstamp)\n{\n    const auto now = high_resolution_clock::now();\n    const auto passedUsec = duration_cast<microseconds>(now - tstamp).count();\n    return passedUsec;\n}\n\n}\n\nnamespace Megaverse\n{\n\nstruct TinyProfiler::TinyProfilerImpl\n{\n    std::map<std::string, tstamp> timestamps;\n    std::map<std::string, microseconds::rep> totalTime;\n};\n\n\nTinyProfiler & TinyProfiler::instance()\n{\n    static TinyProfiler profiler;\n    return profiler;\n}\n\nTinyProfiler & tprof()\n{\n    return TinyProfiler::instance();\n}\n\n}\n\n\nTinyProfiler::TinyProfiler()\n{\n    data = std::make_unique<TinyProfilerImpl>();\n}\n\nvoid TinyProfiler::startTimer(const std::string &key)\n{\n    data->timestamps[key] = high_resolution_clock::now();\n}\n\nvoid TinyProfiler::pauseTimer(const std::string &key)\n{\n    if (!data->timestamps.count(key))\n    {\n        TLOG(ERROR) << \"No such timer: \" << key;\n        return;\n    }\n\n    const auto passedUsec = passedSince(data->timestamps[key]);\n    data->totalTime[key] += passedUsec;\n}\n\nfloat TinyProfiler::readTimer(const std::string &key, bool log)\n{\n    if (!data->timestamps.count(key))\n    {\n        TLOG(ERROR) << \"No such timer: \" << key;\n        return 0.0f;\n    }\n    \n    const auto passedUsec = passedSince(data->timestamps[key]) + data->totalTime[key];\n    TLOG_IF(INFO, log) << passedUsec << \" us passed for \" << key;\n    return float(passedUsec);\n}\n\nfloat TinyProfiler::stopTimer(const std::string &key, bool log)\n{\n    const auto passedUsec = readTimer(key, log);\n    data->timestamps.erase(key);\n    data->totalTime.erase(key);\n    return passedUsec;\n}\n"
  },
  {
    "path": "src/libs/util/src/util.cpp",
    "content": "#include <cstring>\n\n#include <util/util.hpp>\n\n\nnamespace Megaverse\n{\n\nvoid memcpyStride(char *dst, const char *src, int elemSize, int numElements, int ofs, int stride)\n{\n    for (int i = 0, dstOfs = 0, srcOfs = ofs; i < numElements; ++i, dstOfs += elemSize, srcOfs += stride)\n        memcpy(dst + dstOfs, src + srcOfs, elemSize);\n}\n\n}"
  },
  {
    "path": "src/libs/v4r_rendering/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\nproject(libgfx-v4r VERSION 0.1 LANGUAGES CXX)\n\nadd_library_default(v4r_rendering)\ntarget_link_libraries(v4r_rendering util env rendering v4r_headless v4r_debug Magnum::Primitives)\n"
  },
  {
    "path": "src/libs/v4r_rendering/include/v4r_rendering/v4r_env_renderer.hpp",
    "content": "#pragma once\n\n#include <memory>\n\n#include <env/env_renderer.hpp>\n\n\nnamespace Megaverse\n{\n\nclass V4RDrawable;\n\nclass V4REnvRenderer : public EnvRenderer\n{\npublic:\n    /**\n     * @param previousRenderer if renderers are chained (i.e. multiple renderers render the same scene) we need the\n     * pointer to the previous renderer in the chain to provide the list of \"dirty\" drawables whose absolute\n     * transformations we need to query from the scene graph and update.\n     */\n    explicit V4REnvRenderer(Envs &envs, int w, int h, V4REnvRenderer *previousRenderer, bool withOverview);\n\n    ~V4REnvRenderer() override;\n\n    void reset(Env &env, int envIdx) override;\n\n    void preDraw(Env &env, int envIndex) override;\n\n    void draw(Envs &envs) override;\n\n    const uint8_t * getObservation(int envIdx, int agentIdx) const override;\n\n    std::vector<int> getDirtyDrawables(int envIdx) const;\n\n    Overview * getOverview() override;\n\nprivate:\n    struct Impl;\n    std::unique_ptr<Impl> pimpl;\n};\n\n}"
  },
  {
    "path": "src/libs/v4r_rendering/src/v4r_env_renderer.cpp",
    "content": "#include <memory>\n#include <vector>\n\n#include <glm/ext.hpp>\n#include <glm/gtc/type_ptr.hpp>\n\n#include <Magnum/Trade/MeshData.h>\n#include <Magnum/SceneGraph/Camera.h>\n#include <Magnum/SceneGraph/Drawable.h>\n#include <Magnum/SceneGraph/AbstractObject.h>\n\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n#include <v4r.hpp>\n#include <v4r/debug.hpp>\n\n#include <util/tiny_logger.hpp>\n\n#include <rendering/render_utils.hpp>\n\n#include <v4r_rendering/v4r_env_renderer.hpp>\n\n\nusing namespace std;\nusing namespace Magnum;\nusing namespace Magnum::Math::Literals;\n\nusing namespace Megaverse;\n\n\nclass Megaverse::V4RDrawable : public SceneGraph::Drawable3D\n{\npublic:\n    explicit V4RDrawable(\n            SceneGraph::AbstractObject3D &parentObject,\n            v4r::Environment &renderEnv,\n            uint32_t instanceID,\n            SceneGraph::DrawableGroup3D &drawables)\n        : SceneGraph::Drawable3D{parentObject, &drawables},\n          _renderEnv(renderEnv),\n          _instanceID(instanceID)\n    {}\n\nprivate:\n    void draw(const Matrix4 &transformation, SceneGraph::Camera3D &) override\n    {\n        _renderEnv.updateInstanceTransform(_instanceID, glm::make_mat4(transformation.data()));\n    }\n\npublic:\n    void updateAbsoluteTransformation()\n    {\n        _renderEnv.updateInstanceTransform(_instanceID, glm::make_mat4(object().absoluteTransformationMatrix().data()));\n    }\n\nprivate:\n    v4r::Environment &_renderEnv;\n    uint32_t _instanceID;\n};\n\n\nstruct ColorCompare\n{\n    bool operator()(const Magnum::Color3 &c1, const Magnum::Color3 &c2) const\n    {\n        return c1.r() == c2.r() ? c1.g() == c2.g() ? c1.b() < c2.b() : c1.g() < c2.g() : c1.r() < c2.r();\n    }\n};\n\n\nstruct V4REnvRenderer::Impl\n{\npublic:\n    explicit Impl(Envs &envs, int w, int h, V4REnvRenderer *previousRenderer, bool withOverview);\n\n    ~Impl();\n\n    /**\n     * Reset the state of the renderer between episodes.\n     * @param env\n     */\n    void reset(Env &env, int envIdx);\n\n    void preDraw(Env &env, int envIdx);\n    void draw(Envs &envs);\n\n    const uint8_t * getObservation(int envIdx, int agentIdx) const;\n\n    /**\n     * Assuming preDraw() and draw() were already called for this renderer before the next renderer in the chain\n     * requests dirty drawables.\n     */\n    std::vector<int> getDirtyDrawables(int envIdx) const { return dirtyDrawables[envIdx]; }\n\n    Overview * getOverview() { return &overview; }\n\nprivate:\n    int batchSize(const Envs &envs) const\n    {\n        int res = 0;\n        for (const auto &e : envs)\n            res += e->getNumAgents();\n\n        return res;\n    }\n\npublic:\n    v4r::BatchRenderer renderer;\n    v4r::AssetLoader loader;\n    v4r::CommandStream cmdStream;\n    shared_ptr<v4r::Scene> scene;\n    vector<v4r::Environment> renderEnvs;\n\n    glm::u32vec2 framebufferSize;\n\n    int pixelsPerFrame{}, pixelsPerEnv{};\n\n//    vector<uint8_t> cpuFrames;\n\n    std::vector<SceneGraph::DrawableGroup3D> envDrawables;\n    std::vector<std::vector<V4RDrawable *>> v4rDrawables;  // to avoid dynamic cast on every step()\n    std::vector<std::vector<std::reference_wrapper<SceneGraph::AbstractObject3D>>> drawablesObjects;\n\n    std::vector<std::vector<int>> dirtyDrawables;\n\n    std::map<Color3, int, ColorCompare> materialIndices;\n\n//    v4r::RenderDoc rdoc;\n\n    std::map<DrawableType, Trade::MeshData> meshData;\n    std::map<DrawableType, int> meshIndices;\n\n    V4REnvRenderer *previousRenderer = nullptr;\n\n    bool withOverviewCamera = false;\n    Overview overview;\n};\n\nusing Pipeline = v4r::BlinnPhong<v4r::RenderOutputs::Color,\n                                 v4r::DataSource::Uniform,\n                                 v4r::DataSource::Uniform,\n                                 v4r::DataSource::Uniform>;\n\nV4REnvRenderer::Impl::Impl(Envs &envs, int w, int h, V4REnvRenderer *previousRenderer, bool withOverview)\n    : renderer{{ 0, 1, 1, uint32_t(batchSize(envs)), uint32_t(w), uint32_t(h), glm::mat4(1.f) },\n               v4r::RenderFeatures<Pipeline> {v4r::RenderOptions::CpuSynchronization}}\n    , loader{renderer.makeLoader()}\n    , cmdStream{renderer.makeCommandStream()}\n    , renderEnvs{}\n    , framebufferSize{w, h}\n    , previousRenderer{previousRenderer}\n    , withOverviewCamera{withOverview}\n    // cpuFrames(),\n    // rdoc()\n{\n    auto numEnvs = envs.size();\n    envDrawables.resize(numEnvs), drawablesObjects.resize(numEnvs), v4rDrawables.resize(numEnvs), dirtyDrawables.resize(numEnvs);\n\n//    cpuFrames = vector<uint8_t>(size_t(framebufferSize.x * framebufferSize.y * 4 * env.getNumAgents()));\n\n    vector<shared_ptr<v4r::Mesh>> meshes;\n    vector<shared_ptr<v4r::Material>> materials;\n\n    using Vertex = Pipeline::Vertex;\n    using MaterialParams = Pipeline::MaterialParams;\n\n    // Inefficient conversion\n    auto convertMesh = [&](const Magnum::Trade::MeshData &magnum_mesh) {\n        vector<Vertex> vertices;\n        vector<uint32_t> indices;\n        const auto magnum_indices = magnum_mesh.indicesAsArray();\n        const auto magnum_positions = magnum_mesh.positions3DAsArray();\n        const auto magnum_normals = magnum_mesh.normalsAsArray();\n\n        for (size_t i = 0; i < magnum_positions.size(); i++) {\n            const auto &position = magnum_positions[i];\n            const auto &normal = magnum_normals[i];\n\n            vertices.emplace_back(Vertex {\n                glm::make_vec3(position.data()),\n                glm::make_vec3(normal.data())\n            });\n        }\n\n        for (uint32_t idx : magnum_indices)\n            indices.push_back(idx);\n\n        return loader.loadMesh(move(vertices), move(indices));\n    };\n\n    // meshes\n    {\n        initPrimitives(meshData);\n        for (const auto &[drawable, data] : meshData) {\n            meshIndices[drawable] = int(meshes.size());\n            meshes.emplace_back(convertMesh(data));\n        }\n    }\n\n    // Materials\n    {\n        const auto palette = envs.front()->getPalette();\n        constexpr float shininess = 300.0f;\n\n        for (auto c : palette) {\n            materialIndices[c] = int(materials.size());\n\n            materials.emplace_back(loader.makeMaterial(MaterialParams {\n                glm::vec3(c.r(), c.g(), c.b()),\n                glm::vec3(1.f),\n                shininess\n            }));\n        }\n    }\n\n    // Scene\n    { \n        v4r::SceneDescription scene_desc(move(meshes), move(materials));\n        scene_desc.addLight(glm::vec3(0, 4, 2), glm::vec3(0.66f));\n\n        scene = loader.makeScene(scene_desc);\n    }\n\n    // vector of render envs\n    {\n        auto [fov, near, far, aspectRatio] = agentCameraParameters();\n        UNUSED(aspectRatio);\n\n        for (auto &env : envs)\n            for (int agentIdx = 0; agentIdx < env->getNumAgents(); ++agentIdx)\n                renderEnvs.emplace_back(cmdStream.makeEnvironment(scene, fov, near, far));\n    }\n\n    pixelsPerFrame = framebufferSize.x * framebufferSize.y * 4;\n    pixelsPerEnv = envs.front()->getNumAgents() * pixelsPerFrame;\n}\n\nV4REnvRenderer::Impl::~Impl()\n{\n    TLOG(INFO) << __PRETTY_FUNCTION__;\n}\n\nvoid V4REnvRenderer::Impl::reset(Env &env, int envIdx)\n{\n    auto [fov, near, far, aspectRatio] = agentCameraParameters();\n    if (withOverviewCamera && envIdx == 0) {\n        auto [oFov, oNear, oFar, oAspectRatio] = overviewCameraParameters();\n        fov = oFov, near = oNear, far = oFar, aspectRatio = oAspectRatio;\n    }\n    UNUSED(aspectRatio);\n\n    for (int i = 0; i < env.getNumAgents(); ++i) {\n        const auto idx = envIdx * env.getNumAgents() + i;  // assuming all envs have the same numAgents\n        renderEnvs[idx] = cmdStream.makeEnvironment(scene, fov, near, far);\n    }\n\n    // reset renderer data structures\n    {\n        envDrawables[envIdx] = SceneGraph::DrawableGroup3D{};\n    }\n\n    // drawables\n    {\n        const auto &drawables = env.getDrawables();\n\n        for (int agentIdx = 0; agentIdx < env.getNumAgents(); ++agentIdx) {\n            const auto renderEnvIdx = envIdx * env.getNumAgents() + agentIdx;\n            auto &renderEnv = renderEnvs[renderEnvIdx];\n\n            for (const auto &[drawableType, meshIndex] : meshIndices) {\n                for (const auto &sceneObjectInfo : drawables.at(drawableType)) {\n                    const auto &color = sceneObjectInfo.color;\n                    const auto materialIdx = materialIndices[color];  // if we forgot to add the color to the palette, we should crash here\n                    const auto renderID = renderEnv.addInstance(uint32_t(meshIndex), uint32_t(materialIdx), glm::mat4(1.f));\n                    sceneObjectInfo.objectPtr->addFeature<V4RDrawable>(renderEnv, renderID, envDrawables[envIdx]);\n                }\n            }\n        }\n\n        drawablesObjects[envIdx].clear(), v4rDrawables[envIdx].clear();\n\n        for (size_t i = 0; i < envDrawables[envIdx].size(); ++i) {\n            auto &object = envDrawables[envIdx][i].object();\n            drawablesObjects[envIdx].emplace_back(object);\n\n            auto v4rDrawable = dynamic_cast<V4RDrawable *>(&envDrawables[envIdx][i]);\n            v4rDrawables[envIdx].emplace_back(v4rDrawable);\n        }\n\n        dirtyDrawables[envIdx].clear();\n    }\n\n    // controllable overview camera\n    if (withOverviewCamera && envIdx == 0)\n        overview.reset(&env.getScene());\n}\n\nvoid V4REnvRenderer::Impl::preDraw(Env &env, int envIdx)\n{\n    dirtyDrawables[envIdx].clear();\n\n    const auto numAgents = env.getNumAgents();\n    for (int agentIdx = 0; agentIdx < numAgents; ++agentIdx) {\n        const auto renderEnvIdx = envIdx * numAgents + agentIdx;\n        v4r::Environment &renderEnv = renderEnvs[renderEnvIdx];\n\n        auto activeCameraPtr = env.getAgents()[agentIdx]->getCamera();\n        if (withOverviewCamera && overview.enabled && envIdx == 0)\n            activeCameraPtr = overview.camera;\n\n        auto view = glm::make_mat4(activeCameraPtr->cameraMatrix().data());\n\n        renderEnv.setCameraView(view);\n    }\n\n    if (previousRenderer) {\n        dirtyDrawables[envIdx] = previousRenderer->getDirtyDrawables(envIdx);\n    } else {\n        std::vector<std::reference_wrapper<SceneGraph::AbstractObject3D>> dirtyObjects;\n\n        for (size_t i = 0; i < drawablesObjects[envIdx].size(); ++i) {\n            auto &obj = drawablesObjects[envIdx][i].get();\n            if (obj.isDirty()) {\n                dirtyObjects.emplace_back(drawablesObjects[envIdx][i]);\n                dirtyDrawables[envIdx].emplace_back(i);\n            }\n        }\n\n        // Collapsing the scene graph transformations \"manually\", somehow this is barely faster, if at all\n        SceneGraph::AbstractObject3D::setClean(dirtyObjects);\n    }\n\n    for (auto &drawableIdx : dirtyDrawables[envIdx])\n        v4rDrawables[envIdx][drawableIdx]->updateAbsoluteTransformation();\n}\n\nvoid V4REnvRenderer::Impl::draw(Envs &)\n{\n//    rdoc.startFrame();\n    cmdStream.render(renderEnvs);\n    cmdStream.waitForFrame();\n\n//    memcpy(\n//        cpuFrames.data(),\n//        cmdStream.getRGB(),\n//        env.getNumAgents() * framebufferSize.x * framebufferSize.y * 4\n//    );\n\n//    rdoc.endFrame();\n\n//    cudaError_t cuda_res = cudaStreamSynchronize(cudaStream);\n//    if (cuda_res != cudaSuccess)\n//        abort();\n}\n\nconst uint8_t * V4REnvRenderer::Impl::getObservation(int envIdx, int agentIdx) const\n{\n    const auto startIdx = envIdx * pixelsPerEnv;\n    return cmdStream.getRGB() + startIdx + agentIdx * pixelsPerFrame;\n//    return cpuFrames.data() + agentIdx * framebufferSize.x * framebufferSize.y * 4;\n}\n\nV4REnvRenderer::V4REnvRenderer(Envs &envs, int w, int h, V4REnvRenderer *previousRenderer, bool withOverview)\n{\n    pimpl = std::make_unique<Impl>(envs, w, h, previousRenderer, withOverview);\n}\n\nV4REnvRenderer::~V4REnvRenderer() = default;\n\n\nvoid V4REnvRenderer::reset(Env &env, int envIdx)\n{\n    pimpl->reset(env, envIdx);\n}\n\nvoid V4REnvRenderer::preDraw(Env &env, int envIndex)\n{\n    pimpl->preDraw(env, envIndex);\n}\n\nvoid V4REnvRenderer::draw(Envs &envs)\n{\n    pimpl->draw(envs);\n}\n\nconst uint8_t * V4REnvRenderer::getObservation(int envIdx, int agentIdx) const\n{\n    return pimpl->getObservation(envIdx, agentIdx);\n}\n\nstd::vector<int> V4REnvRenderer::getDirtyDrawables(int envIdx) const\n{\n    return pimpl->getDirtyDrawables(envIdx);\n}\n\nOverview * V4REnvRenderer::getOverview()\n{\n    return pimpl->getOverview();\n}\n"
  },
  {
    "path": "src/libs/viewer/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(libviewer VERSION 0.1 LANGUAGES CXX)\n\nif (BUILD_GUI_APPS)\n    find_package(Corrade REQUIRED Main)\n    set(MAGNUM_DEPENDENCIES\n            Corrade::Main\n            Magnum::GL\n            Magnum::Magnum\n            Magnum::MeshTools\n            Magnum::Primitives\n            Magnum::SceneGraph\n            Magnum::Shaders)\n\n    add_library_default(viewer)\n    target_link_libraries(viewer PUBLIC env magnum_rendering ${MAGNUM_DEPENDENCIES} Magnum::Trade Magnum::Application ${OpenCV_LIBS})\n\n    if (NOT CORRADE_TARGET_APPLE)\n        target_link_libraries(viewer PUBLIC v4r_rendering)\n    endif ()\nendif()"
  },
  {
    "path": "src/libs/viewer/include/viewer/viewer.hpp",
    "content": "#pragma once\n\n#include <Magnum/Timeline.h>\n#include <Magnum/ImageView.h>\n#include <Magnum/PixelFormat.h>\n\n#include <Magnum/GL/Buffer.h>\n#include <Magnum/GL/Context.h>\n#include <Magnum/GL/Texture.h>\n#include <Magnum/GL/Renderer.h>\n#include <Magnum/GL/PixelFormat.h>\n#include <Magnum/GL/Version.h>\n#include <Magnum/GL/Framebuffer.h>\n#include <Magnum/GL/TextureFormat.h>\n\n#include <Magnum/GL/Renderbuffer.h>\n#include <Magnum/GL/RenderbufferFormat.h>\n#include <Magnum/GL/DefaultFramebuffer.h>\n\n#include <Magnum/Math/Matrix4.h>\n#include <Magnum/Platform/Sdl2Application.h>\n#include <Magnum/Primitives/Cube.h>\n#include <Magnum/SceneGraph/Camera.h>\n\n#include <env/env_renderer.hpp>\n\n#include <magnum_rendering/rendering_context.hpp>\n\n\nnamespace Megaverse\n{\n\nclass Viewer : public Magnum::Platform::Application\n{\npublic:\n    explicit Viewer(Envs &envs, bool useVulkan, EnvRenderer *parentRenderer, const Arguments &arguments);\n\n    virtual ~Viewer() { viewerExists = false; }\n\npublic:\n    void step(const std::vector<bool> &dones);\n\nprotected:\n    void drawEvent() override;\n\n    void keyPressEvent(KeyEvent &event) override;\n\n    void keyReleaseEvent(KeyEvent &event) override;\n\n    void mouseMoveEvent(MouseMoveEvent &event) override;\n\nprivate:\n    void controlOverview(const KeyEvent::Key &key, bool addAction);\n\n    void moveOverviewCamera();\n\npublic:\n    static bool viewerExists;\n\nprotected:\n    Envs &envs;\n\n    /**\n     * Overview is only supported for the 1st env in case we have a vector of envs.\n     * On-the-fly switching between multiple envs is also possible, but requires additional logic.\n     */\n    constexpr static int activeEnv = 0;\n    int activeAgent = 0;\n\n    std::unique_ptr<EnvRenderer> renderer;\n\n    bool forceReset = false;\n\nprivate:\n    bool useVulkan;\n\n    int width = 1920, height = 1080;\n\n    std::unique_ptr<RenderingContext> ctx;\n\n    bool withDebugDraw = true;\n\n    Action currOverviewAction = Action::Idle;\n\n    Magnum::GL::Framebuffer framebuffer{Magnum::NoCreate};\n    Magnum::GL::Renderbuffer colorBuffer{Magnum::NoCreate};\n};\n\n}\n"
  },
  {
    "path": "src/libs/viewer/src/viewer.cpp",
    "content": "#include <opencv2/core/mat.hpp>\n#include <opencv2/imgproc.hpp>\n\n#include <util/tiny_logger.hpp>\n\n#include <env/env.hpp>\n\n#include <viewer/viewer.hpp>\n\n#include <magnum_rendering/magnum_env_renderer.hpp>\n\n#ifndef CORRADE_TARGET_APPLE\n    #include <v4r_rendering/v4r_env_renderer.hpp>\n#endif\n\n\nusing namespace Magnum;\nusing namespace Megaverse;\n\n\nbool Viewer::viewerExists = false;\n\n\nViewer::Viewer(Envs &envs, bool useVulkan, EnvRenderer *parentRenderer, const Arguments& arguments)\n: Magnum::Platform::Application{arguments, NoCreate}\n, envs{envs}\n, useVulkan{useVulkan}\n{\n    assert(!viewerExists);  // only one viewer per process is supported\n    viewerExists = true;\n\n    // Try 8x MSAA, fall back to zero samples if not possible. Enable only 2x MSAA if we have enough DPI.\n    {\n        const Vector2 dpiScaling = this->dpiScaling({});\n        Configuration conf;\n        conf.setTitle(\"MegaverseViewer\").setSize({width, height}, dpiScaling);\n        GLConfiguration glConf;\n        glConf.setSampleCount(dpiScaling.max() < 2.0f ? 8 : 2);\n\n        if(!tryCreate(conf, glConf)) {\n            TLOG(WARNING) << \"Fall back to default MSAA\";\n            create(conf, glConf.setSampleCount(0));\n        }\n    }\n\n    GL::Renderer::enable(GL::Renderer::Feature::DepthTest);\n    GL::Renderer::enable(GL::Renderer::Feature::FaceCulling);\n\n    ctx = std::make_unique<WindowRenderingContext>();\n\n    const Magnum::Vector2i fbSize = framebufferSize();\n    if (useVulkan) {\n#if defined (CORRADE_TARGET_APPLE)\n        TLOG(ERROR) << \"Vulkan not supported on MacOS\";\n        UNUSED(parentRenderer);\n#else\n        framebuffer = GL::Framebuffer{Range2Di{{}, fbSize}};\n        framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, colorBuffer);\n        framebuffer.mapForDraw({{0, GL::Framebuffer::ColorAttachment{0}}});\n        framebuffer.clearColor(0, Color3{0.125f}).clearDepth(1.0).bind();\n\n        auto v4rParentRenderer = dynamic_cast<V4REnvRenderer *>(parentRenderer);\n        renderer = std::make_unique<V4REnvRenderer>(envs, fbSize[0], fbSize[1], v4rParentRenderer, true);\n#endif\n    } else {\n        renderer = std::make_unique<MagnumEnvRenderer>(envs, fbSize[0], fbSize[1], withDebugDraw, true, ctx.get());\n        dynamic_cast<MagnumEnvRenderer &>(*renderer).toggleDebugMode();\n    }\n\n    for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx)\n        renderer->reset(*envs[envIdx], envIdx);\n\n    setSwapInterval(0);\n\n    TLOG(WARNING) << \"\\nControls:\\n\"\n                  << \"WASD and arrow keys to control the agent\\n\"\n                  << \"1,2,3,4,etc. to switch between agents (if several are present in the environment)\\n\"\n                  << \"Press O to toggle the overview camera, use mouse to control view angle\\n\"\n                  << \"Use UHJK keys to control the position of the camera\\n\"\n                  << \"Press R to reset the episode\\n\"\n                  << \"Press ENTER to toggle Bullet collision debug view (only OpenGL version)\\n\"\n                  << \"ESC to exit the app\\n\";\n}\n\nvoid Viewer::step(const std::vector<bool> &dones)\n{\n    for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx) {\n        if (forceReset)\n            envs[envIdx]->terminateEpisodeOnNextFrame();\n\n        if (dones[envIdx])\n            renderer->reset(*envs[envIdx], envIdx);\n    }\n\n    forceReset = false;\n\n    moveOverviewCamera();\n    redraw();\n}\n\nvoid Viewer::drawEvent()\n{\n    if (useVulkan) {\n#if !defined(CORRADE_TARGET_APPLE)\n        for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx)\n            renderer->preDraw(*envs[envIdx], envIdx);\n\n        renderer->draw(envs);\n        auto dataPtr = renderer->getObservation(activeEnv, activeAgent);\n\n        // probably would've been easier to actually draw a quad upside down instead of flipping the texture\n        // but hey, this is not a performance-critical code and it works!\n        cv::Mat mat(height, width, CV_8UC4, (char *) dataPtr);\n        cv::flip(mat, mat, 0);\n\n        Containers::ArrayView<const uint8_t> data(dataPtr, width * height * 4);\n        ImageView2D image(PixelFormat::RGBA8Unorm, {width, height}, data);\n\n        GL::Texture2D texture;\n        texture.setWrapping(GL::SamplerWrapping::ClampToEdge)\n               .setStorage(int(Math::log2(height)) + 1, GL::TextureFormat::RGBA8, {width, height})\n               .setSubImage(0, {}, image)\n               .generateMipmap();\n\n        framebuffer.mapForRead(GL::Framebuffer::ColorAttachment(0));\n        framebuffer.attachTexture(GL::Framebuffer::ColorAttachment(0), texture, 0);\n\n        // blit color to window framebuffer\n        GL::defaultFramebuffer.bind();\n        GL::AbstractFramebuffer::blit(framebuffer, GL::defaultFramebuffer, {{}, framebuffer.viewport().size()}, GL::FramebufferBlit::Color);\n#endif\n    } else {\n        auto &magnumRenderer = dynamic_cast<MagnumEnvRenderer &>(*renderer);\n\n        for (int envIdx = 0; envIdx < int(envs.size()); ++envIdx) {\n            magnumRenderer.preDraw(*envs[envIdx], envIdx);\n            magnumRenderer.drawAgent(*envs[envIdx], envIdx, activeAgent, false);\n        }\n\n        auto rendererFramebuffer = magnumRenderer.getFramebuffer();\n\n        GL::defaultFramebuffer.bind();\n\n        rendererFramebuffer->mapForRead(GL::Framebuffer::ColorAttachment{0});\n\n        // blit color to window framebuffer\n        GL::AbstractFramebuffer::blit(*rendererFramebuffer, GL::defaultFramebuffer, {{}, rendererFramebuffer->viewport().size()}, GL::FramebufferBlit::Color);\n    }\n\n    swapBuffers();\n}\n\nvoid Viewer::keyPressEvent(Platform::Sdl2Application::KeyEvent &event)\n{\n    auto *overview = renderer->getOverview();\n\n    controlOverview(event.key(), true);\n\n    auto chgAgent = [this](int idx) {\n        if (idx >= envs[0]->getNumAgents())\n            TLOG(WARNING) << \"Could not switch to agent \" << idx << \" (greater than numAgents)\";\n        else\n            activeAgent = idx;\n    };\n\n    switch (event.key()) {\n        case KeyEvent::Key::One:\n            chgAgent(0);\n            break;\n        case KeyEvent::Key::Two:\n            chgAgent(1);\n            break;\n        case KeyEvent::Key::Three:\n            chgAgent(2);\n            break;\n        case KeyEvent::Key::Four:\n            chgAgent(3);\n            break;\n        case KeyEvent::Key::Five:\n            chgAgent(4);\n            break;\n        case KeyEvent::Key::Six:\n            chgAgent(5);\n            break;\n        case KeyEvent::Key::R:\n            forceReset = true;\n            break;\n        case KeyEvent::Key::O:\n            overview->enabled = !overview->enabled;\n            setCursor(overview->enabled ? Cursor::HiddenLocked : Cursor::Arrow);\n            break;\n        case KeyEvent::Key::Enter:\n            if (!useVulkan)\n                dynamic_cast<MagnumEnvRenderer &>(*renderer).toggleDebugMode();\n            break;\n        case KeyEvent::Key::Esc:\n            setCursor(Cursor::Arrow);\n            exit(0);\n            std::exit(0);\n        default:\n            break;\n    }\n\n    event.setAccepted();\n}\n\nvoid Viewer::keyReleaseEvent(Platform::Sdl2Application::KeyEvent &event)\n{\n    controlOverview(event.key(), false);\n    event.setAccepted();\n}\n\nvoid Viewer::mouseMoveEvent(Platform::Sdl2Application::MouseMoveEvent &event)\n{\n    auto *overview = renderer->getOverview();\n    if (!overview->enabled)\n        return;\n\n    constexpr float sensitivity = 0.075;\n    const auto horizontalMove = float(event.relativePosition().x());\n    const auto verticalMove = -float(event.relativePosition().y());\n\n    const auto yRotation = Deg(horizontalMove);\n    overview->root->rotateYLocal(-sensitivity * yRotation);\n\n    const auto verticalRotation = sensitivity * verticalMove;\n    auto newRotation = overview->verticalRotation + verticalRotation;\n    newRotation = std::min(newRotation, 89.0f);\n    newRotation = std::max(newRotation, -89.0f);\n\n    const auto rotationDelta = newRotation - overview->verticalRotation;\n    const auto xRotation = Deg(rotationDelta);\n    overview->verticalTilt->rotateXLocal(xRotation);\n    overview->verticalRotation = newRotation;\n\n    overview->saveTransformation();\n\n    event.setAccepted();\n    redraw();\n}\n\nvoid Viewer::controlOverview(const KeyEvent::Key &key, bool addAction)\n{\n    auto a = Action::Idle;\n\n    switch(key) {\n        case KeyEvent::Key::U: a = Action::Forward; break;\n        case KeyEvent::Key::J: a = Action::Backward; break;\n        case KeyEvent::Key::H: a = Action::Left; break;\n        case KeyEvent::Key::K: a = Action::Right; break;\n        case KeyEvent::Key::LeftShift: a = Action::LookUp; break;\n        case KeyEvent::Key::RightShift: a = Action::LookDown; break;\n\n        default: break;\n    }\n\n    if (a == Action::Idle)\n        return;\n\n    if (addAction)\n        currOverviewAction |= a;\n    else\n        currOverviewAction &= ~a;\n\n    redraw();\n}\n\nvoid Viewer::moveOverviewCamera()\n{\n    auto *overview = renderer->getOverview();\n    if (!overview->enabled)\n        return;\n\n    const float speed = 0.6;\n\n    Vector3 moveDirection{};\n\n    const auto backwardDirection = overview->verticalTilt->absoluteTransformation().backward();\n\n    if (!!(currOverviewAction & Action::Forward))\n        moveDirection -= backwardDirection;\n    else if (!!(currOverviewAction & Action::Backward))\n        moveDirection += backwardDirection;\n\n    const auto rightDirection = overview->verticalTilt->absoluteTransformation().right();\n\n    if (!!(currOverviewAction & Action::Left))\n        moveDirection -= rightDirection;\n    else if (!!(currOverviewAction & Action::Right))\n        moveDirection += rightDirection;\n\n    const auto upDirection = Vector3{0, 1, 0};\n\n    if (!!(currOverviewAction & Action::LookUp))\n        moveDirection += upDirection;\n    else if (!!(currOverviewAction & Action::LookDown))\n        moveDirection -= upDirection;\n\n    if (moveDirection.length() > FLT_EPSILON)\n        overview->root->translate(speed * moveDirection.normalized());\n\n    overview->saveTransformation();\n}\n"
  },
  {
    "path": "src/test/CMakeLists.txt",
    "content": "add_test_default(run_unit_tests)\ntarget_link_libraries(run_unit_tests gtest gtest_main util magnum_rendering env mazes scenarios)\n"
  },
  {
    "path": "src/test/src/env_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <Magnum/GL/Context.h>\n\n#include <env/env.hpp>\n#include <scenarios/init.hpp>\n\n#include <magnum_rendering/magnum_env_renderer.hpp>\n\n\nusing namespace Megaverse;\n\n\nclass EnvTest : public ::testing::Test {\nprotected:\n    virtual void SetUp() { scenariosGlobalInit(); }\n};\n\n\nTEST_F(EnvTest, env)\n{\n    Env env{\"TowerBuilding\"};\n}\n\nTEST_F(EnvTest, multipleEnvs)\n{\n    Envs envs;\n    for (int i = 0; i < 3; ++i) {\n        auto e = std::make_unique<Env>(\"TowerBuilding\");\n        e->reset();\n        envs.emplace_back(std::move(e));\n    }\n\n    MagnumEnvRenderer renderer{envs, 128, 72};\n\n    for (int i = 0; i < 3; ++i)\n        renderer.reset(*envs[i], i);\n\n    for (int i = 0; i < 3; ++i)\n        renderer.draw(envs);\n}\n"
  },
  {
    "path": "src/test/src/filesystem_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <util/tiny_logger.hpp>\n#include <util/filesystem_utils.hpp>\n\n\nnamespace Megaverse\n{\n\nTEST(filesystem, pathJoin)\n{\n    const std::string t1{\"abc\"}, t2{\"def\"}, t3{\"ghi\"};\n    const auto p1{pathJoin(t1)}, p2{pathJoin(t1, t2)}, p3{pathJoin(t1, t2, t3)};\n    EXPECT_EQ(p1, t1);\n    EXPECT_EQ(p2, t1 + pathDelim() + t2);\n    EXPECT_EQ(p3, t1 + pathDelim() + t2 + pathDelim() + t3);\n}\n\n}"
  },
  {
    "path": "src/test/src/gfx_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <magnum_rendering/rendering_context.hpp>\n\nusing namespace Megaverse;\n\n\nTEST(gfx, context)\n{\n    // this will only work if the GPU is present\n    constexpr int device = 0;\n    WindowlessContext context{device};\n}\n"
  },
  {
    "path": "src/test/src/logger_tests.cpp",
    "content": "#include <thread>\n\n#include <gtest/gtest.h>\n\n#include <util/tiny_logger.hpp>\n#include <util/string_utils.hpp>\n\n\nusing namespace Megaverse;\n\n#define TST_LOG(level) LogMessage(level, __FILE__, __LINE__, __FUNCTION__, &testStream)()\n\n\nnamespace\n{\n\n// helper functions\n\nvoid testLog(std::ostringstream &testStream, int threadIdx)\n{\n    constexpr int n = 5000;\n    for (int i = 0; i < n; ++i)\n        TST_LOG(INFO) << \"thread_\" << threadIdx;\n}\n\n}\n\n\n/// Let multiple threads write log messages to the same stream,\n/// then parse the output and verify that none of the output is messed up\n/// (e.g. no overlapping messages \"thread_thread_21, etc.)\nTEST(logger, concurrency)\n{\n    // stream that stores log output during this test, so we can actually verify the results\n    std::ostringstream testStream;\n\n    constexpr int numThreads = 10;\n    std::vector<std::thread> threads;\n    threads.reserve(numThreads);\n    for (int i = 0; i < numThreads; ++i)\n        threads.emplace_back(testLog, std::ref(testStream), i + 1);\n\n    for (int i = 0; i < numThreads; ++i)\n        threads[i].join();\n\n    std::vector<std::string> lines = Megaverse::splitString(testStream.str(), \"\\n\");\n    int threadIdx = 0;\n    for (auto &line : lines)\n    {\n        const auto msg = splitString(line, \" \").back();\n        EXPECT_TRUE(startsWith(msg, \"thread_\"));\n        EXPECT_LE(msg.length(), 10);\n        std::istringstream(splitString(msg, \"_\").back()) >> threadIdx;\n\n        EXPECT_GE(threadIdx, 1);\n        EXPECT_LE(threadIdx, numThreads);\n    }\n}\n"
  },
  {
    "path": "src/test/src/maze_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <util/tiny_logger.hpp>\n\n#include <mazes/kruskal.h>\n#include <mazes/honeycombmaze.h>\n\n\nusing namespace Megaverse;\n\n\nTEST(maze, honeycomb)\n{\n    const auto size = 5;\n    auto *maze = new HoneyCombMaze{size};\n    auto *algorithm = new Kruskal;\n\n    TLOG(DEBUG) << \"Initialising graph...\";\n    maze->InitialiseGraph();\n    TLOG(DEBUG) << \"Generating maze...\";\n    maze->GenerateMaze(algorithm);\n\n    const auto outputprefix = \"/tmp/maze\";\n    TLOG(DEBUG) << \"Rendering maze to '\" << outputprefix << \".svg'...\";\n    maze->PrintMazeSVG(outputprefix);\n\n    auto adjList = maze->getAdjacencyList();\n    const auto [xmin, ymin, xmax, ymax] = maze->GetCoordinateBounds();\n    TLOG(DEBUG) << xmin << \" \" << ymin << \" \" << xmax << \" \" << ymax;\n\n    TLOG(DEBUG) << system(\"eog /tmp/maze.svg\");\n}\n"
  },
  {
    "path": "src/test/src/noise_test.cpp",
    "content": "#include <cassert>\n#include <iostream>\n#include <fstream>\n#include <sstream>\n\n#include <gtest/gtest.h>\n\n#include <util/util.hpp>\n#include <util/perlin_noise.hpp>\n\n\nusing namespace Megaverse;\n\n\n# pragma pack (push, 1)\nstruct BMPHeader\n{\n    std::uint16_t bfType;\n    std::uint32_t bfSize;\n    std::uint16_t bfReserved1;\n    std::uint16_t bfReserved2;\n    std::uint32_t bfOffBits;\n    std::uint32_t biSize;\n    std::int32_t  biWidth;\n    std::int32_t  biHeight;\n    std::uint16_t biPlanes;\n    std::uint16_t biBitCount;\n    std::uint32_t biCompression;\n    std::uint32_t biSizeImage;\n    std::int32_t  biXPelsPerMeter;\n    std::int32_t  biYPelsPerMeter;\n    std::uint32_t biClrUsed;\n    std::uint32_t biClrImportant;\n};\n\nstatic_assert(sizeof(BMPHeader) == 54);\n# pragma pack (pop)\n\nstruct RGB\n{\n    double r = 0.0;\n    double g = 0.0;\n    double b = 0.0;\n    constexpr RGB() = default;\n    explicit constexpr RGB(double _rgb) noexcept\n        : r(_rgb), g(_rgb), b(_rgb) {}\n    constexpr RGB(double _r, double _g, double _b) noexcept\n        : r(_r), g(_g), b(_b) {}\n};\n\nclass Image\n{\nprivate:\n\n    std::vector<RGB> m_data;\n\n    std::int32_t m_width = 0, m_height = 0;\n\n    bool inBounds(std::int32_t y, std::int32_t x) const noexcept\n    {\n        return (0 <= y) && (y < m_height) && (0 <= x) && (x < m_width);\n    }\n\n    static constexpr std::uint8_t ToUint8(double x) noexcept\n    {\n        return x >= 1.0 ? 255 : x <= 0.0 ? 0 : static_cast<std::uint8_t>(x * 255.0 + 0.5);\n    }\n\npublic:\n\n    Image() = default;\n\n    Image(std::size_t width, std::size_t height)\n        : m_data(width * height)\n          , m_width(static_cast<std::int32_t>(width))\n          , m_height(static_cast<std::int32_t>(height)) {}\n\n    void set(std::int32_t x, std::int32_t y, const RGB& color)\n    {\n        if (!inBounds(y, x))\n        {\n            return;\n        }\n\n        m_data[static_cast<std::size_t>(y) * m_width + x] = color;\n    }\n\n    std::int32_t width() const\n    {\n        return m_width;\n    }\n\n    std::int32_t height() const\n    {\n        return m_height;\n    }\n\n    bool saveBMP(const std::string& path)\n    {\n        const std::int32_t  rowSize = m_width * 3 + m_width % 4;\n        const std::uint32_t bmpsize = rowSize * m_height;\n        const BMPHeader header =\n            {\n                0x4d42,\n                static_cast<std::uint32_t>(bmpsize + sizeof(BMPHeader)),\n                0,\n                0,\n                sizeof(BMPHeader),\n                40,\n                m_width,\n                m_height,\n                1,\n                24,\n                0,\n                bmpsize,\n                0,\n                0,\n                0,\n                0\n            };\n\n        if (std::ofstream ofs{ path, std::ios_base::binary })\n        {\n            ofs.write(reinterpret_cast<const char*>(&header), sizeof(header));\n\n            std::vector<std::uint8_t> line(rowSize);\n\n            for (std::int32_t y = m_height - 1; -1 < y; --y)\n            {\n                size_t pos = 0;\n\n                for (std::int32_t x = 0; x < m_width; ++x)\n                {\n                    const RGB& col = m_data[static_cast<std::size_t>(y) * m_width + x];\n                    line[pos++] = ToUint8(col.b);\n                    line[pos++] = ToUint8(col.g);\n                    line[pos++] = ToUint8(col.r);\n                }\n\n                ofs.write(reinterpret_cast<const char*>(line.data()), line.size());\n            }\n\n            return true;\n        }\n        else\n        {\n            return false;\n        }\n    }\n};\n//\n//void testNoise()\n//{\n//    siv::PerlinNoise perlinA(std::random_device{});\n//    siv::PerlinNoise perlinB;\n//\n//    std::array<std::uint8_t, 256> state;\n//    perlinA.serialize(state);\n//    perlinB.deserialize(state);\n//\n//    assert(perlinA.octaveNoise(0.1, 0.2, 0.3, 4)\n//           == perlinB.octaveNoise(0.1, 0.2, 0.3, 4));\n//\n//    perlinA.reseed(1234);\n//    perlinB.reseed(1234);\n//\n//    assert(perlinA.octaveNoise(0.1, 0.2, 0.3, 4)\n//           == perlinB.octaveNoise(0.1, 0.2, 0.3, 4));\n//\n//    perlinA.reseed(std::mt19937{ 1234 });\n//    perlinB.reseed(std::mt19937{ 1234 });\n//\n//    assert(perlinA.octaveNoise(0.1, 0.2, 0.3, 4)\n//           == perlinB.octaveNoise(0.1, 0.2, 0.3, 4));\n//}\n\n\nTEST(util, perlinNoise)\n{\n//    testNoise();\n\n    Image image(51, 21);\n\n    std::cout << \"---------------------------------\\n\";\n    std::cout << \"* frequency [0.1 .. 8.0 .. 64.0] \\n\";\n    std::cout << \"* octaves   [1 .. 8 .. 16]       \\n\";\n    std::cout << \"* seed      [0 .. 2^32-1]        \\n\";\n    std::cout << \"---------------------------------\\n\";\n\n    Megaverse::Rng rng{std::random_device{}()};\n\n    for (int i = 0; i < 10; ++i) {\n        double frequency = double (randRange(1, 60, rng)) / 10.0;\n        std::cout << \"double frequency = \" << frequency << \"\\n\";\n        frequency = std::clamp(frequency, 0.1, 64.0);\n\n        std::int32_t octaves = randRange(1, 4, rng);\n        std::cout << \"int32 octaves    = \" << octaves << \"\\n\";\n        octaves = std::clamp(octaves, 1, 16);\n\n        std::uint32_t seed = randRange(0, 1000000000, rng);\n        std::cout << \"uint32 seed      = \" << seed << \"\\n\";\n\n        const siv::PerlinNoise perlin(seed);\n        const double fx = image.width() / frequency;\n        const double fy = image.height() / frequency;\n\n        for (std::int32_t y = 0; y < image.height(); ++y) {\n            for (std::int32_t x = 0; x < image.width(); ++x) {\n                const RGB color(perlin.accumulatedOctaveNoise2D_0_1(x / fx, y / fy, octaves));\n                image.set(x, y, color);\n            }\n        }\n\n        std::stringstream ss;\n        ss << 'f' << frequency << 'o' << octaves << '_' << seed << \".bmp\";\n\n        if (image.saveBMP(ss.str())) {\n            std::cout << \"...saved \\\"\" << ss.str() << \"\\\"\\n\";\n        } else {\n            std::cout << \"...failed\\n\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/src/string_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <util/string_utils.hpp>\n\n\nusing namespace Megaverse;\n\n\nTEST(str, startsWith)\n{\n    EXPECT_TRUE(startsWith(\"abc\", \"a\"));\n    EXPECT_TRUE(startsWith(\"abc\", \"ab\"));\n    EXPECT_TRUE(startsWith(\"abc\", \"abc\"));\n    EXPECT_TRUE(startsWith(\"abc\", \"\"));\n    EXPECT_FALSE(startsWith(\"abc\", \"abcd\"));\n    EXPECT_FALSE(startsWith(\"abc\", \"b\"));\n    EXPECT_TRUE(startsWith(\"\", \"\"));\n    EXPECT_FALSE(startsWith(\"\", \"a\"));\n}\n\nTEST(str, endsWith)\n{\n    EXPECT_TRUE(endsWith(\"abc\", \"c\"));\n    EXPECT_TRUE(endsWith(\"abc\", \"bc\"));\n    EXPECT_TRUE(endsWith(\"abc\", \"abc\"));\n    EXPECT_TRUE(endsWith(\"abc\", \"\"));\n    EXPECT_FALSE(endsWith(\"abc\", \"_abc\"));\n    EXPECT_FALSE(endsWith(\"abc\", \"b\"));\n    EXPECT_TRUE(endsWith(\"\", \"\"));\n    EXPECT_FALSE(endsWith(\"\", \"a\"));\n}\n"
  },
  {
    "path": "src/test/src/util_tests.cpp",
    "content": "#include <algorithm>\n\n#include <gtest/gtest.h>\n\n#include <util/util.hpp>\n\n\nusing namespace Megaverse;\n\n\nTEST(util, memcpyStride)\n{\n    char buf[] = { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1 };\n    char zeros[9], ones[6];\n\n    memcpyStride(zeros, buf, 3, 3, 0, 5);\n    auto range = std::equal_range(std::begin(zeros), std::end(zeros), 0);\n    EXPECT_TRUE(range.first == std::begin(zeros) && range.second == std::end(zeros));\n\n    memcpyStride(ones, buf, 2, 3, 3, 5);\n    range = std::equal_range(std::begin(ones), std::end(ones), 1);\n    EXPECT_TRUE(range.first == std::begin(ones) && range.second == std::end(ones));\n}\n"
  },
  {
    "path": "src/test/src/voxel_grid_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <util/voxel_grid.hpp>\n\n#include <env/voxel_state.hpp>\n\n\nusing namespace Megaverse;\n\n\nstruct TestVoxelState\n{\n    int someInt;\n    std::string someString;\n};\n\n\nTEST(voxelGrid, basic)\n{\n    VoxelGrid<TestVoxelState> vg{100, {0, 0, 0}, 1};\n\n    VoxelCoords coords{1, 2, 3};\n    EXPECT_EQ(coords, VoxelCoords(1, 2, 3));  // make sure operator== works\n\n    EXPECT_EQ(vg.getCoords({1.5, 2.3, 3.2}), coords);\n\n    auto voxelPtr = vg.get({0, 0, 0});\n    EXPECT_EQ(voxelPtr, nullptr);\n\n    TestVoxelState state{3, \"42\"};\n    vg.set({0, 0, 0}, state);\n\n    voxelPtr = vg.get({0, 0, 0});\n    EXPECT_NE(voxelPtr, nullptr);\n\n    const auto newStr = \"I love voxels!\";\n    voxelPtr->someInt = 42;\n    voxelPtr->someString = newStr;\n\n    auto ptr = vg.get({0, 0, 0});\n    EXPECT_EQ(voxelPtr, ptr);\n    EXPECT_EQ(ptr->someInt, 42);\n    EXPECT_EQ(ptr->someString, newStr);\n}\n\nTEST(voxelGrid, perf)\n{\n    VoxelGrid<TestVoxelState> vg{100, {0, 0, 0}, 1};\n\n    for (int x = 0; x < 100; ++x)\n        for (int y = 0; y < 100; ++y)\n            for (int z = 0; z < 100; ++z)\n                vg.set({x, y, z}, {x + y + z, \"42\"});\n}\n\nTEST(voxelGrid, voxelState)\n{\n    VoxelGrid<VoxelState> vg{0, {0, 0, 0}, 1};\n\n    vg.set({0, 1, 2}, VoxelState{});\n\n    TLOG(INFO) << sizeof(vg) << \" \" << sizeof(*vg.get({0, 1, 2}));\n}"
  }
]