[
  {
    "path": ".gitattributes",
    "content": "# -----------------------------------------------------------------------------\n# After much research...\n#  text should be auto, it's the only sane cross-platform option\n#\n#  See:  http://stackoverflow.com/a/10855862\n#  See also: http://adaptivepatchwork.com/2012/03/01/mind-the-end-of-your-line/\n#\n#  To squelch extraneous messages on windows, run:\n#     git --config core.autocrlf=true\n#\n#  To stay consistent on OS X and Linux, run:\n#     git --config core.autocrlf=input\n# -----------------------------------------------------------------------------\n* text eol=auto\n\n# SOA binary asset files:\n*.png   binary\n*.ogg   binary\n*.ico   binary\n\n# Visual Studio files:\n*.pbxproj binary merge=union\n*.vcxproj text merge=union\n*.sln text merge=union\n\n# Windows binary project files:\n*.exe   binary\n*.dll   binary\n*.lib   binary\n*.a     binary\n*.hpp   binary\n\n# Language aware diffs and force line endings if git did not know they are text:\n*.h     text diff=cpp\n*.hpp   text diff=cpp\n*.inl   text diff=cpp\n*.cpp   text diff=cpp\n*.py    text diff=python\n*.cs    text diff=csharp\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.sln.docstates\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\nx64/\nbuild/\n_build/\n_clang/\n_ninja/\n_debug/\nbld/\n[Bb]in/\n[Oo]bj/\n*.i\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n#NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n*.cachefile\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding addin-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n*.ncrunch*\n_NCrunch_*\n.*crunch*.local.xml\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n\n# NuGet Packages Directory\npackages/\n## TODO: If the tool you use requires repositories.config uncomment the next line\n#!packages/repositories.config\n\n# Enable \"build/\" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets\n# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented)\n!packages/build/\n\n# Windows Azure Build Output\ncsx/\n*.build.csdef\n\n# Windows Store app package directory\nAppPackages/\n\n# Others\nsql/\n*.Cache\nClientBin/\n[Ss]tyle[Cc]op.*\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file to a newer\n# Visual Studio version. Backup files are not needed, because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n#OS junk files\n[Tt]humbs.db\n*.DS_Store\ndesktop.ini\n\n# Python files\n*.pyc\n\n# A Folder To Put Personal Stuff\nMine/\n\n#VS2015 openDB\n*.opendb\n\n.vscode/\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"game\"]\n\tpath = game\n\turl = https://github.com/RegrowthStudios/SoAGameData.git\n[submodule \"Vorb\"]\n\tpath = Vorb\n\turl = https://github.com/RegrowthStudios/Vorb.git\n"
  },
  {
    "path": ".mailmap",
    "content": "Benjamin Arnold <brb555@utk.edu> barnold1953 <brb555@utk.edu>\nBrian Bruggeman <brian.m.bruggeman@gmail.com> <Brian.M.Bruggeman@gmail.com> Brian <brian.m.bruggeman@gmail.com>\nCristian Zaloj <czaloj@gmail.com> <cz68@cornell.edu> Cristian Zaloj <cz68@cornell.edu> czaloj <cz68@cornell.edu>\nFrank McCoy <jaxfrank@comcast.net>\nJesse <jessenic@digiex.net> jessenic <jessenic@digiex.net>\n"
  },
  {
    "path": ".travis.yml",
    "content": "# OSX/Linux (https://github.com/travis-ci-tester/toolchain-table)\n\nlanguage:\n  - cpp\n\n# Container-based infrastructure (Linux)\n# * https://docs.travis-ci.com/user/migrating-from-legacy/#How-can-I-use-container-based-infrastructure%3F\nsudo:\n  - false\n\n# Install packages differs for container-based infrastructure\n# * https://docs.travis-ci.com/user/migrating-from-legacy/#How-do-I-install-APT-sources-and-packages%3F\n# List of available packages:\n# * https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-trusty\n# List of available sources:\n# * https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json\naddons:\n  apt:\n    sources:\n      - ubuntu-toolchain-r-test\n    packages:\n      - python3-pip\n      - g++-7\n      - g++-8\n\ndist:\n  - trusty\n\nenv:\n  global:\n  #soa\n    - secure: \"LIcgKhksDL/NoBH9YpAggZMbppx53DhzUP8AkHfIH6vZ9Gq2ZuRN8KFj7SeCQX7qBJmv+vtGrW0ZdXHNXYNgEgnuqOjwdX3Z5ccAmrsuq41Qh3Hki+K3wKPKzenJxL6bF/UxTRUQipoKEP6EQS/WRkZejP7SS/YQBgmAx3eLAqx7N6LJxBgvUmKgaGAfaODjAeix7faasPMlFDVqfWn6+kbOirUEwBNxGUXJrSi1OupMwlhrNmhEoFqfRSkDbcMi5914wE126c3vG3bKSNBzCN6hSlO++knidZVaWnxwZm8Oq1SXpzLmr3YmiiWxiK5bo+LpIow00C7Iq5k3IA+otJD4NdLShU7x8jzryeI+4VQlo2UVF01Ssq/xboVJoWdF+RT2PFaKB3eJiBiXWfN2BVMr75sWj+7qb1o0KwZZtpa+qFQxuVPLKQuZ/fW6AI/ybk7NoHM3K7csPioJERlhQQ9fOTasqEOiGYCKhdjrP3Zg2sHjSlITQ68Jb+q8O/ku4taRiWprQ82/wtzMI4Yo6CdcLvtXHoXgdIPSJp/5x1/HotdSIK9n4Si6vOYNW0jtRVIc5L8neVScHEDOdhejxw0s7jArA3MMnWB6o9TS2oDv4uzPhHd+wyr86oiUT/HQq8jXUMbKSc0asFVf276b9TRTxcW7WdjveoznorDuIYE=\" \n  #krazer\n#    - secure: \"inNq/wQPDmZlK1IOwe2DPryyRZWZxg3qAJ6/KZ/zeg8/lQvkwPAzwcp9QM/zf2rzDvNBJ/ZOIwO0lcOpXlyAt6hhhSrD0T/T1HObu1F6Iv9cMy1i8fvu3RH27Kp5eIepHeGINo3uEIlyR3XZbA8Ir0jPBc2XFWkK6WyJm00wsKozlFH1PXboekClWcXL7TJWyP5FV96L9vYDa7uorFe1ct8jSkot3dTKpg4782mZNTLH+T2GgVSmkoyMzsnNwHmz11gHo+opm3LVC9sbIhjym+iwQ0CGQwdX7B6bu/v4yiHoMqBxG2d9zrB6YiG1Aa8x4KbBauc9I9NK7Xvk/e8lthCk0rcU+TXJJKciAJKVzjYkPCRsXOK/awb5YmbBsQpvWUXPztc84soCtFf6xEH6JMKJqrL76CKr30XXNJvum4MO0q8IaM7XH2+VjxxjrjU/g3WKhJZr3sXzYWqJvG7r8ZtmsohZPEUewckw5R4AXPNEjhLMIu+/M2CC86xbIWwdHrhQuM/03LDNIdqfzMINmQAewdEzJ/aF3SdVwoE94n4eeC68KjckcqRzvcPI0My3Wr1lq4ON61rQGgCNJWC2GDOYES5DK2bgoE2fJS4ULEL4R9CXnI47kFGAW6cH7StjZkWP+VqbkdEFSxuvq54mMYC7CdrTiMC2Zfm9PuAZtQY=\"\n\n\nmatrix:\n  include:\n    # Linux {\n\n    - os: linux\n      env: >\n        TOOLCHAIN=clang-cxx17\n        PROJECT_DIR=./\n\n    - os: linux\n      env: >\n        TOOLCHAIN=gcc-7-cxx17\n        PROJECT_DIR=./\n\n    - os: linux\n      env: >\n        TOOLCHAIN=gcc-8-cxx17\n        PROJECT_DIR=./\n\n#can not compile glew\n#    - os: linux\n#      env: >\n#        TOOLCHAIN=android-ndk-r17-api-21-arm64-v8a-neon-clang-libcxx14\n#        PROJECT_DIR=./\n#\n#    - os: linux\n#      env: >\n#        TOOLCHAIN=analyze-cxx17\n#        PROJECT_DIR=./\n#\n#    - os: linux\n#      env: >\n#        TOOLCHAIN=sanitize-address-cxx17\n#        PROJECT_DIR=./\n#\n#    - os: linux\n#      env: >\n#        TOOLCHAIN=sanitize-leak-cxx17\n#        PROJECT_DIR=./\n#\n#    - os: linux\n#      env: >\n#        TOOLCHAIN=sanitize-thread-cxx17\n#        PROJECT_DIR=./\n\n    # }\n\n    # OSX {\n\n#compile issues with templates\n#    - os: osx\n#      osx_image: xcode9.4\n#      env: >\n#        TOOLCHAIN=osx-10-13-make-cxx14\n#        PROJECT_DIR=./\n#\n#    - os: osx\n#      osx_image: xcode9.4\n#      env: >\n#        TOOLCHAIN=osx-10-13-cxx14\n#        PROJECT_DIR=./\n#\n#lua not packaged correctly for mac/ios\n#    - os: osx\n#      osx_image: xcode9.4\n#      env: >\n#        TOOLCHAIN=ios-nocodesign-11-4-dep-9-3\n#        PROJECT_DIR=./\n\n    # }\n\ninstall:\n  # Info about OS\n  - uname -a\n\n  # Info about available disk space\n  - df -h $HOME\n\n  # Disable autoupdate\n  # * https://github.com/Homebrew/brew/blob/7d31a70373edae4d8e78d91a4cbc05324bebc3ba/Library/Homebrew/manpages/brew.1.md.erb#L202\n  - export HOMEBREW_NO_AUTO_UPDATE=1\n\n  # Install Python 3\n  - if [[ \"`uname`\" == \"Darwin\" ]]; then travis_retry brew upgrade python || echo \"Ignoring failure...\"; fi\n  - if [[ \"`uname`\" == \"Darwin\" ]]; then travis_retry brew install python3; fi\n\n  # Install Python package 'requests'\n  # 'easy_install3' is not installed by 'brew install python3' on OS X 10.9 Maverick\n  - if [[ \"`uname`\" == \"Darwin\" ]]; then pip3 install requests; fi\n  - if [[ \"`uname`\" == \"Darwin\" ]]; then pip3 install gitpython; fi\n  - if [[ \"`uname`\" == \"Linux\" ]]; then travis_retry pip3 install --user requests; fi\n  - if [[ \"`uname`\" == \"Linux\" ]]; then travis_retry pip3 install --user gitpython; fi\n\n  # Install latest Polly toolchains and scripts\n  - wget https://github.com/ruslo/polly/archive/master.zip\n  - unzip master.zip\n  - POLLY_ROOT=\"`pwd`/polly-master\"\n  - export PATH=\"${POLLY_ROOT}/bin:${PATH}\"\n\n  # Install dependencies (CMake, Android NDK)\n  - install-ci-dependencies.py --prune-archives\n\n  # Tune locations\n  - export PATH=\"`pwd`/_ci/cmake/bin:${PATH}\"\n\n  # Installed if toolchain is Android (otherwise directory doesn't exist)\n  - export ANDROID_NDK_r10e=\"`pwd`/_ci/android-ndk-r10e\"\n  - export ANDROID_NDK_r11c=\"`pwd`/_ci/android-ndk-r11c\"\n  - export ANDROID_NDK_r15c=\"`pwd`/_ci/android-ndk-r15c\"\n  - export ANDROID_NDK_r16b=\"`pwd`/_ci/android-ndk-r16b\"\n  - export ANDROID_NDK_r17=\"`pwd`/_ci/android-ndk-r17\"\n\nscript:\n  - python3 ./jenkins.py\n\n# https://docs.travis-ci.com/user/customizing-the-build/#Whitelisting-or-blacklisting-branches\nbranches:\n  except:\n    - /^pr\\..*/\n    - /^v[0-9]+\\.[0-9]+\\.[0-9]+$/\n\ngit:\n  submodules: false\n\nbefore_script:\n  git submodule update --init Vorb "
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required (VERSION 3.0)\n\nset(HUNTER_STATUS_DEBUG ON)\n#setup cache server and suppot upload\nset(\n    HUNTER_CACHE_SERVERS\n    \"https://github.com/huntercache/SoA\"\n    CACHE\n    STRING\n    \"Default cache server\"\n)\n\nstring(COMPARE EQUAL \"$ENV{TRAVIS}\" \"true\" is_travis)\nstring(COMPARE EQUAL \"$ENV{APPVEYOR}\" \"True\" is_appveyor)\nstring(COMPARE EQUAL \"$ENV{GITHUB_USER_PASSWORD}\" \"\" password_is_empty)\n\nif((is_travis OR is_appveyor) AND NOT password_is_empty)\n  option(HUNTER_RUN_UPLOAD \"Upload cache binaries\" ON)\nendif()\n\nmessage(STATUS \"Travis: ${is_travis}\")\nmessage(STATUS \"Appveyor: ${is_appveyor}\")\nmessage(STATUS \"Password empty: ${password_is_empty}\")\nmessage(STATUS \"Hunter upload: ${HUNTER_RUN_UPLOAD}\")\n\n\nset(\n    HUNTER_PASSWORDS_PATH\n    \"${CMAKE_CURRENT_LIST_DIR}/cmake/hunter/passwords.cmake\"\n    CACHE\n    FILEPATH\n    \"Hunter passwords\"\n)\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/cmake/hunter/HunterGate.cmake)\n\nHunterGate(\n    URL \"https://github.com/cpp-pm/hunter/archive/v0.23.222.tar.gz\"\n    SHA1 \"0b88baaa2a9a35b8ce632c57ade66be8dd918afd\"\n)\n\nset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)\n\nproject(SoA)\n\n#if(\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"MSVC\")\n#  if(MSVC_VERSION GREATER 1900)\n#    message(FATAL_ERROR \"Only Visual Studio 2015 and below are currently supported.\")\n#  endif()\n#endif()\n\nadd_subdirectory(Vorb)\nadd_subdirectory(SoA)\n\n\n\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2018 Regrowth Studios\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."
  },
  {
    "path": "ModTest/ModTest.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{C49943E6-5645-4D1C-A5F6-FE2D7C94D924}</ProjectGuid>\n    <RootNamespace>ModTest</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\ModTest\\</IntDir>\n    <TargetName>mod</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\ModTest\\</IntDir>\n    <TargetName>mod</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\ModTest\\</IntDir>\n    <TargetName>mod</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\ModTest\\</IntDir>\n    <TargetName>mod</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"main.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "ModTest/ModTest.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"main.cpp\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "ModTest/main.cpp",
    "content": "#include <cstdio>\n\n#define _WINSOCKAPI_\n#include <Windows.h>\n\nBOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {\n    // Perform actions based on the reason for calling.\n    switch (fdwReason) {\n    case DLL_PROCESS_ATTACH:\n        // Initialize once for each new process.\n        puts(\"Mod Attach\");\n        fprintf(stderr, \"DLL\");\n        break;\n    case DLL_THREAD_ATTACH:\n        // Do thread-specific initialization.\n        puts(\"Mod Thread Attach\");\n        break;\n    case DLL_THREAD_DETACH:\n        // Do thread-specific cleanup.\n        puts(\"Mod Thread Detach\");\n        break;\n    case DLL_PROCESS_DETACH:\n        // Perform any necessary cleanup.\n        puts(\"Mod Detach\");\n        break;\n    }\n    return TRUE;\n}\n\nextern \"C\" __declspec(dllexport) int getCode() {\n    return 42;\n}\n"
  },
  {
    "path": "ProjectConverter/App.Designer.cs",
    "content": "﻿namespace ProjectConverter {\n    partial class App {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing) {\n            if(disposing && (components != null)) {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent() {\n            this.comboBox1 = new System.Windows.Forms.ComboBox();\n            this.groupBox1 = new System.Windows.Forms.GroupBox();\n            this.groupBox2 = new System.Windows.Forms.GroupBox();\n            this.checkBox1 = new System.Windows.Forms.CheckBox();\n            this.log = new System.Windows.Forms.RichTextBox();\n            this.tabControl1 = new System.Windows.Forms.TabControl();\n            this.tabPage1 = new System.Windows.Forms.TabPage();\n            this.tabPage2 = new System.Windows.Forms.TabPage();\n            this.files = new System.Windows.Forms.ListBox();\n            this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();\n            this.button1 = new System.Windows.Forms.Button();\n            this.button2 = new System.Windows.Forms.Button();\n            this.groupBox1.SuspendLayout();\n            this.groupBox2.SuspendLayout();\n            this.tabControl1.SuspendLayout();\n            this.tabPage1.SuspendLayout();\n            this.tabPage2.SuspendLayout();\n            this.tableLayoutPanel1.SuspendLayout();\n            this.SuspendLayout();\n            // \n            // comboBox1\n            // \n            this.comboBox1.Dock = System.Windows.Forms.DockStyle.Fill;\n            this.comboBox1.FormattingEnabled = true;\n            this.comboBox1.Items.AddRange(new object[] {\n            \"None\"});\n            this.comboBox1.Location = new System.Drawing.Point(3, 16);\n            this.comboBox1.Name = \"comboBox1\";\n            this.comboBox1.Size = new System.Drawing.Size(385, 21);\n            this.comboBox1.TabIndex = 0;\n            this.comboBox1.Text = \"None\";\n            this.comboBox1.DropDown += new System.EventHandler(this.comboBox1_DropDown);\n            this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);\n            // \n            // groupBox1\n            // \n            this.groupBox1.Controls.Add(this.comboBox1);\n            this.groupBox1.Dock = System.Windows.Forms.DockStyle.Top;\n            this.groupBox1.Location = new System.Drawing.Point(0, 0);\n            this.groupBox1.Name = \"groupBox1\";\n            this.groupBox1.Size = new System.Drawing.Size(391, 43);\n            this.groupBox1.TabIndex = 1;\n            this.groupBox1.TabStop = false;\n            this.groupBox1.Text = \"VS Processes\";\n            // \n            // groupBox2\n            // \n            this.groupBox2.Controls.Add(this.checkBox1);\n            this.groupBox2.Dock = System.Windows.Forms.DockStyle.Bottom;\n            this.groupBox2.Location = new System.Drawing.Point(0, 317);\n            this.groupBox2.Name = \"groupBox2\";\n            this.groupBox2.Size = new System.Drawing.Size(391, 51);\n            this.groupBox2.TabIndex = 2;\n            this.groupBox2.TabStop = false;\n            this.groupBox2.Text = \"Options\";\n            // \n            // checkBox1\n            // \n            this.checkBox1.AutoSize = true;\n            this.checkBox1.Dock = System.Windows.Forms.DockStyle.Fill;\n            this.checkBox1.Location = new System.Drawing.Point(3, 16);\n            this.checkBox1.Name = \"checkBox1\";\n            this.checkBox1.Size = new System.Drawing.Size(385, 32);\n            this.checkBox1.TabIndex = 0;\n            this.checkBox1.Text = \"Close On Process Termination\";\n            this.checkBox1.UseVisualStyleBackColor = true;\n            this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged);\n            // \n            // log\n            // \n            this.log.Dock = System.Windows.Forms.DockStyle.Fill;\n            this.log.Location = new System.Drawing.Point(3, 3);\n            this.log.Name = \"log\";\n            this.log.Size = new System.Drawing.Size(377, 242);\n            this.log.TabIndex = 3;\n            this.log.Text = \"\";\n            // \n            // tabControl1\n            // \n            this.tabControl1.Controls.Add(this.tabPage1);\n            this.tabControl1.Controls.Add(this.tabPage2);\n            this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;\n            this.tabControl1.Location = new System.Drawing.Point(0, 43);\n            this.tabControl1.Name = \"tabControl1\";\n            this.tabControl1.SelectedIndex = 0;\n            this.tabControl1.Size = new System.Drawing.Size(391, 274);\n            this.tabControl1.TabIndex = 4;\n            // \n            // tabPage1\n            // \n            this.tabPage1.Controls.Add(this.log);\n            this.tabPage1.Location = new System.Drawing.Point(4, 22);\n            this.tabPage1.Name = \"tabPage1\";\n            this.tabPage1.Padding = new System.Windows.Forms.Padding(3);\n            this.tabPage1.Size = new System.Drawing.Size(383, 248);\n            this.tabPage1.TabIndex = 0;\n            this.tabPage1.Text = \"Log\";\n            this.tabPage1.UseVisualStyleBackColor = true;\n            // \n            // tabPage2\n            // \n            this.tabPage2.Controls.Add(this.tableLayoutPanel1);\n            this.tabPage2.Controls.Add(this.files);\n            this.tabPage2.Location = new System.Drawing.Point(4, 22);\n            this.tabPage2.Name = \"tabPage2\";\n            this.tabPage2.Padding = new System.Windows.Forms.Padding(3);\n            this.tabPage2.Size = new System.Drawing.Size(383, 248);\n            this.tabPage2.TabIndex = 1;\n            this.tabPage2.Text = \"Files\";\n            this.tabPage2.UseVisualStyleBackColor = true;\n            // \n            // files\n            // \n            this.files.Dock = System.Windows.Forms.DockStyle.Fill;\n            this.files.FormattingEnabled = true;\n            this.files.Location = new System.Drawing.Point(3, 3);\n            this.files.Name = \"files\";\n            this.files.Size = new System.Drawing.Size(377, 242);\n            this.files.TabIndex = 0;\n            // \n            // tableLayoutPanel1\n            // \n            this.tableLayoutPanel1.ColumnCount = 2;\n            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));\n            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));\n            this.tableLayoutPanel1.Controls.Add(this.button2, 1, 0);\n            this.tableLayoutPanel1.Controls.Add(this.button1, 0, 0);\n            this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;\n            this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 192);\n            this.tableLayoutPanel1.Name = \"tableLayoutPanel1\";\n            this.tableLayoutPanel1.RowCount = 1;\n            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));\n            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));\n            this.tableLayoutPanel1.Size = new System.Drawing.Size(377, 53);\n            this.tableLayoutPanel1.TabIndex = 1;\n            // \n            // button1\n            // \n            this.button1.Dock = System.Windows.Forms.DockStyle.Fill;\n            this.button1.Location = new System.Drawing.Point(3, 3);\n            this.button1.Name = \"button1\";\n            this.button1.Size = new System.Drawing.Size(182, 47);\n            this.button1.TabIndex = 0;\n            this.button1.Text = \"Add\";\n            this.button1.UseVisualStyleBackColor = true;\n            this.button1.Click += new System.EventHandler(this.button1_Click);\n            // \n            // button2\n            // \n            this.button2.Dock = System.Windows.Forms.DockStyle.Fill;\n            this.button2.Location = new System.Drawing.Point(191, 3);\n            this.button2.Name = \"button2\";\n            this.button2.Size = new System.Drawing.Size(183, 47);\n            this.button2.TabIndex = 1;\n            this.button2.Text = \"Remove\";\n            this.button2.UseVisualStyleBackColor = true;\n            this.button2.Click += new System.EventHandler(this.button2_Click);\n            // \n            // App\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(391, 368);\n            this.Controls.Add(this.tabControl1);\n            this.Controls.Add(this.groupBox2);\n            this.Controls.Add(this.groupBox1);\n            this.Name = \"App\";\n            this.Text = \"VS File Changer\";\n            this.groupBox1.ResumeLayout(false);\n            this.groupBox2.ResumeLayout(false);\n            this.groupBox2.PerformLayout();\n            this.tabControl1.ResumeLayout(false);\n            this.tabPage1.ResumeLayout(false);\n            this.tabPage2.ResumeLayout(false);\n            this.tableLayoutPanel1.ResumeLayout(false);\n            this.ResumeLayout(false);\n\n        }\n        #endregion\n\n        private System.Windows.Forms.ComboBox comboBox1;\n        private System.Windows.Forms.GroupBox groupBox1;\n        private System.Windows.Forms.GroupBox groupBox2;\n        private System.Windows.Forms.RichTextBox log;\n        private System.Windows.Forms.CheckBox checkBox1;\n        private System.Windows.Forms.TabControl tabControl1;\n        private System.Windows.Forms.TabPage tabPage1;\n        private System.Windows.Forms.TabPage tabPage2;\n        private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;\n        private System.Windows.Forms.ListBox files;\n        private System.Windows.Forms.Button button2;\n        private System.Windows.Forms.Button button1;\n\n    }\n}"
  },
  {
    "path": "ProjectConverter/App.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.0,Profile=Client\"/>\n    </startup>\n</configuration>\n"
  },
  {
    "path": "ProjectConverter/App.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Drawing;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Windows.Forms;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.IO;\n\nnamespace ProjectConverter {\n    public partial class App : Form {\n        const int NO_PROCESS = 0;\n        Process[] vsProcesses;\n        Process vsProcess;\n        Thread tProcessTermination, tProcessPoll;\n        Dictionary<int, List<FileInfo>> trackedFiles;\n\n        public App() {\n            InitializeComponent();\n            trackedFiles = new Dictionary<int, List<FileInfo>>();\n            trackedFiles[NO_PROCESS] = new List<FileInfo>();\n            log.AppendText(\"Please Select A List Of Files To Track\\n\");\n            log.AppendText(\"Select A Process To Track, If Necessary\\n\");\n        }\n\n        void RebuildProcessList() {\n            // Find Processes\n            var processes = Process.GetProcesses();\n            vsProcesses = processes.Where((p) => {\n                return p.ProcessName.Equals(\"devenv\");\n            }).ToArray();\n\n            // Add Processes\n            comboBox1.Items.Clear();\n            comboBox1.Items.Add(\"None\");\n            if(vsProcesses.Length > 0) {\n                foreach(var p in vsProcesses) {\n                    comboBox1.Items.Add(p.MainWindowTitle);\n                }\n            }\n        }\n        List<FileInfo> GetTrackMap() {\n            List<FileInfo> l;\n            int id = vsProcess == null ? NO_PROCESS : vsProcess.Id;\n            if(!trackedFiles.TryGetValue(id, out l)) {\n                l = new List<FileInfo>();\n                trackedFiles[id] = l;\n            }\n            return l;\n        }\n\n        void VSProcessWaiter() {\n            vsProcess.WaitForExit();\n            if(checkBox1.Checked) {\n                Process.GetCurrentProcess().Kill();\n            }\n            else {\n                vsProcess = null;\n                Invoke((MethodInvoker)delegate { \n                    RebuildProcessList();\n                    comboBox1.SelectedIndex = 0;\n                });\n            }\n        }\n        void VSProcessPoller() {\n            while(true) {\n                var remoteFiles = GetTrackMap();\n                if(remoteFiles.Count != 0) {\n                    var files = new FileInfo[remoteFiles.Count];\n                    remoteFiles.CopyTo(files);\n                    foreach(var fi in remoteFiles) {\n                        Convert(fi);\n                    }\n                }\n                Thread.Sleep(2000);\n            }\n        }\n        void CreateProcessThreads() {\n            if(vsProcess == null) return;\n            tProcessTermination = new Thread(VSProcessWaiter);\n            tProcessTermination.Priority = ThreadPriority.BelowNormal;\n            tProcessTermination.Start();\n            tProcessPoll = new Thread(VSProcessPoller);\n            tProcessPoll.Priority = ThreadPriority.BelowNormal;\n            tProcessPoll.Start();\n        }\n        void TerminateProcessThreads() {\n            if(tProcessTermination != null && tProcessTermination.ThreadState == System.Threading.ThreadState.Running) {\n                tProcessTermination.Abort();\n                tProcessTermination = null;\n            }\n            if(tProcessPoll != null && tProcessPoll.ThreadState == System.Threading.ThreadState.Running) {\n                tProcessPoll.Abort();\n                tProcessPoll = null;\n            }\n        }\n        void Convert(FileInfo fi) {\n            string data;\n            try {\n                using(var s = fi.OpenRead()) {\n                    data = new StreamReader(s).ReadToEnd();\n                }\n                Regex rgx = new Regex(@\"<(?<Outer>\\w+) Include=(?<Name>[^>]+)>\\s+<(?<Inner>\\w+)>(?<Data>[^<]+)</\\k<Inner>>\\s+</\\k<Outer>>\");\n                if(rgx.Match(data).Success) {\n                    data = rgx.Replace(data,\n                        @\"<${Outer} Include=${Name}><${Inner}>${Data}</${Inner}></${Outer}>\"\n                        );\n                    using(var s = fi.Create()) {\n                        var w = new StreamWriter(s);\n                        w.Write(data);\n                        w.Flush();\n                    }\n                    Invoke((MethodInvoker)delegate {\n                        log.AppendText(\"Modified: \" + fi.FullName + \"\\n\");\n                    });\n                }\n            }\n            catch(Exception e) {\n                Invoke((MethodInvoker)delegate {\n                    log.AppendText(\"Error: \" + fi.FullName + \"\\n\");\n                    log.AppendText(e.Message + \"\\n\");\n                });\n            }\n            return;\n\n        }\n\n        // Process Selection\n        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) {\n            TerminateProcessThreads();\n            files.Items.Clear();\n            files.Items.AddRange((from fi in GetTrackMap() select fi.FullName).ToArray());\n\n            if(comboBox1.SelectedIndex == 0) {\n                vsProcess = null;\n            }\n            else {\n                vsProcess = vsProcesses[comboBox1.SelectedIndex - 1];\n                CreateProcessThreads();\n            }\n        }\n        // Process Refresh\n        void comboBox1_DropDown(object sender, System.EventArgs e) {\n            RebuildProcessList();\n        }\n        // Auto-Shutdown Detection\n        private void checkBox1_CheckedChanged(object sender, EventArgs e) {\n            if(checkBox1.Checked) {\n                if(tProcessTermination == null && vsProcess != null) {\n                    CreateProcessThreads();\n                }\n            }\n            else {\n                TerminateProcessThreads();\n            }\n        }\n        // Add Tracked File\n        private void button1_Click(object sender, EventArgs e) {\n            var l = GetTrackMap();\n            using(var fd = new OpenFileDialog()) {\n                fd.ShowDialog();\n                foreach(var f in fd.FileNames) {\n                    FileInfo fi = new FileInfo(f);\n                    if(!l.Contains(fi, new FileNameComparer())) {\n                        l.Add(fi);\n                    }\n                }\n            }\n            files.Items.Clear();\n            files.Items.AddRange((from fi in l select fi.FullName).ToArray());\n        }\n        // Removed Tracked File\n        private void button2_Click(object sender, EventArgs e) {\n            var l = GetTrackMap();\n            foreach(var file in files.SelectedItems) {\n                FileInfo fi = new FileInfo(file.ToString());\n                l.RemoveAll((f) => { return f.FullName.Equals(fi.FullName); });\n            }\n            files.Items.Clear();\n            files.Items.AddRange((from fi in l select fi.FullName).ToArray());\n        }\n        class FileNameComparer : IEqualityComparer<FileInfo> {\n            public bool Equals(FileInfo x, FileInfo y) {\n                return x.FullName.Equals(y.FullName);\n            }\n            public int GetHashCode(FileInfo obj) {\n                return obj.FullName.GetHashCode();\n            }\n        }\n\n        [STAThread]\n        static void Main(string[] args) {\n            using(App app = new App()) {\n                app.ShowDialog();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ProjectConverter/App.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <metadata name=\"files.Locked\" type=\"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n  <metadata name=\"files.Locked\" type=\"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n</root>"
  },
  {
    "path": "ProjectConverter/ProjectConverter.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{75075CEE-B74F-4E21-8C88-D64ACD182237}</ProjectGuid>\n    <OutputType>WinExe</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>ProjectConverter</RootNamespace>\n    <AssemblyName>ProjectConverter</AssemblyName>\n    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <TargetFrameworkProfile>Client</TargetFrameworkProfile>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup>\n    <StartupObject>ProjectConverter.App</StartupObject>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Drawing\" />\n    <Reference Include=\"System.Windows.Forms\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"App.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"App.Designer.cs\">\n      <DependentUpon>App.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"App.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <EmbeddedResource Include=\"App.resx\">\n      <DependentUpon>App.cs</DependentUpon>\n    </EmbeddedResource>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "ProjectConverter/ProjectConverter.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 2013\nVisualStudioVersion = 12.0.21005.1\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ProjectConverter\", \"ProjectConverter.csproj\", \"{75075CEE-B74F-4E21-8C88-D64ACD182237}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{75075CEE-B74F-4E21-8C88-D64ACD182237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{75075CEE-B74F-4E21-8C88-D64ACD182237}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{75075CEE-B74F-4E21-8C88-D64ACD182237}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{75075CEE-B74F-4E21-8C88-D64ACD182237}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "ProjectConverter/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"ProjectConverter\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"ProjectConverter\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2014\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"e74470a1-41b5-431f-9d38-5ebd4d57c105\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "README.md",
    "content": "\n[![dicord](https://img.shields.io/discord/459062989094649866.svg?logo=discord \"Discord\")](https://discord.gg/QRex8GK)\n![travis](https://img.shields.io/travis/RegrowthStudios/SoACode-Public/develop.svg?style=flat-square&label=Linux \"Travis CI\")\n![appveyor](https://img.shields.io/appveyor/ci/SamThePsychoticLeprechaun/soacode-public/develop.svg?style=flat-square&label=Windows \"AppVeyor CI\")\n\n# Seed of Andromeda\nThis repository contains the source code for Seed of Andromeda.\n\n## Getting Started\nThis guide will walk you through setting up as a contributor to the\nSeed of Andromeda project. There is a basic requirement of having several\npackages installed prior to being able to develop. We support all three\nmajor operating systems: Windows, Mac and Linux.\n\n### Contributing\nBefore beginning your SoA journey, please take a moment to use the following resources\nto get an idea of how to contribute, what you might be able to contribute to specifically,\nand to meet some of the other contributors.\n* [Wiki](https://github.com/RegrowthStudios/SoACode-Public/wiki)\n* [Issues](https://github.com/RegrowthStudios/SoACode-Public/issues)\n* [Discord](https://discord.gg/QRex8GK)\n\n### Setting Up:\n**IMPORTANT**: Before following any of the instructions linked below for the platforms we support,\nplease do take a second to fork the repository! If you are new to GitHub, you can \ndo so by clicking the \"fork\" button on the top right of this page.\n\nIf you have cloned the repository before forking, no worries! We can fix it, by following [these instructions](#fixing-a-pre-fork-clone).\n\nNow we're forked, follow the link to the section on setting up for your OS of choice:\n* [Windows](#windows)\n* [Mac](#mac)\n* [Linux](#linux)\n\n### Building:\nNow you have a copy of the code, and perhaps have played with it a little, why not give it\na whirl?\n* [Building](#building-1)\n\n\n## Setting Up\n\n### Windows\n\n#### Prerequisites\n*  Compiler: [Microsoft Visual Studio 2015 (only)](https://visualstudio.microsoft.com/)\n*  Software Version Control:  [Git](http://git-scm.com/downloads)\n*  (Optional) MSVS SVC Plugin:  [MSVS Git Plugin](http://msdn.microsoft.com/en-us/library/hh850437.aspx)\n*  (Optional) TortoiseGit: [tortoisegit](https://tortoisegit.org/download)\n\n### Mac\n\n#### Prerequisites\n* Compiler: [Xcode](https://developer.apple.com/xcode/)\n* Software Version Control: [Git](http://git-scm.com/downloads)\n    Optionally, with [Homebrew](http://brew.sh/):\n    ```brew install git```\n* Preferred editor: [Sublime Text](http://www.sublimetext.com/) and optional packages\n    * [PackageControl](https://sublime.wbond.net/installation)\n    * [CMake](https://sublime.wbond.net/packages/CMake) - CMake.tmLanguage\n    * [GitGutter](https://sublime.wbond.net/packages/GitGutter) - A Sublime Text 2/3 plugin to see git diff in gutter\n    * [SublimeCodeIntel](https://sublime.wbond.net/packages/SublimeCodeIntel) - Full-featured code intelligence and smart autocomplete engine\n    * [SublimeLinter](https://sublime.wbond.net/packages/SublimeLinter) -- Interactive code linting framework for Sublime Text 3\n    * [SublimeLinter-cpplint](https://sublime.wbond.net/packages/SublimeLinter-cpplint) -- This linter plugin for SublimeLinter provides an interface to cpplint.\n    * [SublimeLinter-pep8](https://sublime.wbond.net/packages/SublimeLinter-pep8) - SublimeLinter plugin for python, using pep8.\n    * [SublimeLinter-contrib-clang](https://sublime.wbond.net/packages/SublimeLinter-contrib-clang) - https://sublime.wbond.net/packages/SublimeLinter-contrib-clang\n\n### Linux\n\n#### Prerequisites\n* Compiler: gcc or clang\n    * Install per your preferred operating system package control...\n    * Portage:\n    ```bash\n    sudo emerge -DuNqa gcc   # for gcc\n    sudo emerge -DuNqa clang  # for clang\n    ```\n    * PacMan:\n    ```bash\n    sudo pacman -S gcc\n    sudo pacman -S clang\n    ```\n    * Apt:\n    ```bash\n    sudo apt-get install gcc\n    sudo apt-get install clang\n    ```\n    * Yum:\n    ```bash\n    sudo yum install gcc\n    sudo yum install clang\n    ```\n* Software Version Control: [Git](http://git-scm.com/downloads)\n    * Portage:\n    ```bash\n    sudo emerge -DuNqa git\n    ```\n    * PacMan:\n    ```bash\n    sudo pacman -S git\n    ```\n    * Apt:\n    ```bash\n    sudo apt-get install git\n    ```\n    * Yum:\n    ```bash\n    sudo yum install git\n    ```\n\n# Setup\n1. Create a folder to hold the repositories and change to directory\n    * Windows\n    ```cmd\n    Windows + R\n    cmd\n        \n    cd c:\\\n    mkdir -p repos\n    cd c:\\repos\n    ```\n    * Linux\n    ```bash\n    mkdir ~/repos\n    cd ~/repos\n    ```\n    * Mac\n    ```bash\n    cmd + space\n    Terminal\n        \n    mkdir ~/repos\n    cd ~/repos\n    ```\n2. Clone the Seed of Andromeda repositories\n```cmd\ngit clone --recurse-submodules https://github.com/YOUR_GITHUB_NAME/SoACode-Public.git soa\n```\n3. Change to soa direcotory\n    * Windows\n    ```\n    cd c:\\repos\\soa\n    ```\n    * Linux & Mac\n    ```\n    cd ~/repos/soa\n    ```\n4. (optional) Do this step only if you plan to fork your own Vorb or SoAGameData repos.\n    * Fork both the [Vorb](https://github.com/RegrowthStudios/Vorb) and/or [GameData](https://github.com/RegrowthStudios/SoAGameData) repos in github.\n    * Set origin of submodules to your forked repositories\n    ```cmd\n    # Assuming we're already inside the top-level directory of your SoACode-Public repository.\n    cd Vorb\n    git remote set-url origin https://github.com/YOUR_GITHUB_NAME/Vorb.git\n    cd game\n    git remote set-url origin https://github.com/YOUR_GITHUB_NAME/SoAGameData.git\n    ```\n\n# Building\n\n1. Pull latest code (from inside .../repos/soa)\n    ```bash\n    git checkout develop    # or your current branch\n    git pull --recurse-submodules\n    ```\n2. Run the build script (--help for options)\n    * Windows:\n    ```cmd\n    build.bat    # or compile from within your Visual Studio environment\n    ```\n    * Linux:\n    ```bash\n    ./build.sh\n    ```\n3. Run the built executable\n    * Windows:\n    ```cmd\n    build/SoA/launch-soa-{Release|Debug}.cmd    # or launch from within your Visual Studio environment\n    ```\n    * Linux:\n    ```bash\n    ./build/SoA/launch-soa.sh\n    ```\n\n# Fixing a Pre-Fork Clone\n\nSo, you've accidentally cloned the repository before forking it, eh? No problem. Just run the following git commands inside of the repository and everything will be as it should be!\n\nFirstly, if you still haven't, fork the repositories you want to contribute to!\n\nNow you have a fork we want to set `origin` of each of your local repositories (which is the default remote repository to push changes to) to your corresponding forked repositories:\n```bash\n# Assuming we're already inside the top-level directory of your SoACode-Public repository.\ngit remote set-url origin https://github.com/YOUR_GITHUB_NAME/SoACode-Public.git\ncd Vorb\ngit remote set-url origin https://github.com/YOUR_GITHUB_NAME/Vorb.git\ncd game\ngit remote set-url origin https://github.com/YOUR_GITHUB_NAME/SoAGameData.git\n```\nIf you haven't forked, either Vorb or SoAGameData as you don't intend to contribute to that repository, then you don't need to do run the commands corresponding to that repository.\n\nThat's it! It's all fixed. :)\n"
  },
  {
    "path": "SoA/AABBCollidableComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"AABBCollidableComponentUpdater.h\"\n\n#include \"GameSystem.h\"\n#include \"SpaceSystem.h\"\n#include \"BlockPack.h\"\n\n#include \"VoxelSpaceConversions.h\"\n\nvoid AABBCollidableComponentUpdater::update(GameSystem* gameSystem, SpaceSystem* spaceSystem) {\n    for (auto& it : gameSystem->aabbCollidable) {\n        collideWithVoxels(it.second, gameSystem, spaceSystem);\n    }\n}\n\nvoid AABBCollidableComponentUpdater::collideWithVoxels(AabbCollidableComponent& cmp, GameSystem* gameSystem, SpaceSystem* spaceSystem) {\n    // Clear old data\n    cmp.voxelCollisions.clear();\n    // Get needed components\n    auto& physics = gameSystem->physics.get(cmp.physics);\n    auto& position = gameSystem->voxelPosition.get(physics.voxelPosition);\n    if (position.parentVoxel == 0) return;\n    auto& sphericalVoxel = spaceSystem->sphericalVoxel.get(position.parentVoxel);\n    f64v3 vpos = position.gridPosition.pos + f64v3(cmp.offset - cmp.box * 0.5f);\n    i32v3 vp(glm::floor(vpos));\n    \n    i32v3 bounds(glm::ceil(f64v3(cmp.box) + glm::fract(vpos)));\n    ChunkGrid& grid = sphericalVoxel.chunkGrids[position.gridPosition.face];\n    const BlockPack* bp = sphericalVoxel.blockPack;\n\n    std::map<ChunkID, std::vector<ui16>> boundedVoxels;\n\n    // Get bounded voxels\n    for (int yi = 0; yi < bounds.y; yi++) {\n        for (int zi = 0; zi < bounds.z; zi++) {\n            for (int xi = 0; xi < bounds.x; xi++) {\n                i32v3 p = vp + i32v3(xi, yi, zi);\n                i32v3 cpos = VoxelSpaceConversions::voxelToChunk(p);\n                // TODO(Ben): Negative numbers?\n                ChunkID chunkID(cpos);\n                i32v3 cp = p - cpos * CHUNK_WIDTH;\n                boundedVoxels[chunkID].push_back(cp.y * CHUNK_LAYER + cp.z * CHUNK_WIDTH + cp.x);\n            }\n        }\n    }\n\n    // Find Collidable voxels\n    for (auto& it : boundedVoxels) {\n        ChunkHandle chunk = grid.accessor.acquire(it.first);\n        if (chunk->genLevel == GEN_DONE) {\n            std::lock_guard<std::mutex> l(chunk->dataMutex);\n            for (auto& i : it.second) {\n                BlockID id = chunk->blocks.get(i);\n                if (bp->operator[](id).collide) {\n                    // TODO(Ben): Don't need to look up every time.\n                    cmp.voxelCollisions[it.first].emplace_back(id, i);\n                }\n            }\n        }\n        chunk.release();\n    }\n\n    // Helper macro for below code\n#define CHECK_CODE(dir) \\\n    /* Acquire new chunk if needed */ \\\n    if (id != currentID) { \\\n        /* Release current chunk */ \\\n        if (chunk.isAquired()) { \\\n            chunk->dataMutex.unlock(); \\\n            chunk.release(); \\\n        } \\\n        chunk = grid.accessor.acquire(id); \\\n        if (chunk->genLevel != GEN_DONE) { \\\n            chunk.release(); \\\n            currentID = ChunkID(0xffffffffffffffffu); \\\n        } else { \\\n            chunk->dataMutex.lock(); \\\n            currentID = id; \\\n            /* Check the voxel */ \\\n            if (chunk->genLevel == GEN_DONE && bp->operator[](chunk->blocks.get(index)).collide) { \\\n                cd.dir = true; \\\n            } \\\n        } \\\n    } else {\\\n        /* Check the voxel */ \\\n        if (chunk->genLevel == GEN_DONE && bp->operator[](chunk->blocks.get(index)).collide) { \\\n            cd.dir = true; \\\n        } \\\n    }\n\n    // Set neighbor collide flags\n    // TODO(Ben): More than top\n    ChunkID currentID(0xffffffffffffffffu);\n    ChunkHandle chunk;\n    for (auto& it : cmp.voxelCollisions) {\n        for (auto& cd : it.second) {\n            { // Left\n                ChunkID id = it.first;\n                int index = (int)cd.index;\n                if ((index & 0x1f) == 0) {\n                    index += CHUNK_WIDTH_M1;\n                    id.x--;\n                } else {\n                    index--;\n                }\n                CHECK_CODE(left);\n            }\n            { // Right\n                ChunkID id = it.first;\n                int index = (int)cd.index;\n                if ((index & 0x1f) == CHUNK_WIDTH_M1) {\n                    index -= CHUNK_WIDTH_M1;\n                    id.x++;\n                } else {\n                    index++;\n                }\n                CHECK_CODE(right);\n            }\n            { // Bottom\n                ChunkID id = it.first;\n                int index = (int)cd.index;\n                if (index < CHUNK_LAYER) {\n                    index += (CHUNK_SIZE - CHUNK_LAYER);\n                    id.y--;\n                } else {\n                    index -= CHUNK_LAYER;\n                }\n                CHECK_CODE(bottom);\n            }\n            { // Top\n                ChunkID id = it.first;\n                int index = (int)cd.index;\n                if (index >= CHUNK_SIZE - CHUNK_LAYER) {\n                    index -= (CHUNK_SIZE - CHUNK_LAYER);\n                    id.y++;\n                } else {\n                    index += CHUNK_LAYER;\n                }\n                CHECK_CODE(top);\n            }\n            { // Back\n                ChunkID id = it.first;\n                int index = (int)cd.index;\n                if ((index & 0x3ff) / CHUNK_WIDTH == 0) {\n                    index += (CHUNK_LAYER - CHUNK_WIDTH);\n                    id.z--;\n                } else {\n                    index -= CHUNK_WIDTH_M1;\n                }\n                CHECK_CODE(back);\n            }\n            { // Front\n                ChunkID id = it.first;\n                int index = (int)cd.index;\n                if ((index & 0x3ff) / CHUNK_WIDTH == CHUNK_WIDTH_M1) {\n                    index -= (CHUNK_LAYER - CHUNK_WIDTH);\n                    id.z++;\n                } else {\n                    index += CHUNK_WIDTH_M1;\n                }\n                CHECK_CODE(front);\n            }\n        }\n    }\n    // Release chunk if needed\n    if (chunk.isAquired()) {\n        chunk->dataMutex.unlock();\n        chunk.release();\n    }\n#undef CHECK_CODE\n}\n"
  },
  {
    "path": "SoA/AABBCollidableComponentUpdater.h",
    "content": "//\n// AABBCollidableComponentUpdater.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 30 Aug 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Updater for AABB components.\n//\n\n#pragma once\n\n#ifndef AABBCollidableComponentUpdater_h__\n#define AABBCollidableComponentUpdater_h__\n\n#include <Vorb/ecs/Entity.h>\n\nclass GameSystem;\nclass SpaceSystem;\nstruct AabbCollidableComponent;\n\nclass AABBCollidableComponentUpdater {\npublic:\n    void update(GameSystem* gameSystem, SpaceSystem* spaceSystem);\n\nprivate:\n    void collideWithVoxels(AabbCollidableComponent& cmp, GameSystem* gameSystem, SpaceSystem* spaceSystem);\n};\n\n#endif // AABBCollidableComponentUpdater_h__\n"
  },
  {
    "path": "SoA/ARProcessor.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ARProcessor.h\""
  },
  {
    "path": "SoA/ARProcessor.h",
    "content": "///\n/// ARProcessor.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 9 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Stores and keeps track of Augmented Reality information\n///\n\n#pragma once\n\n#ifndef ARProcessor_h__\n#define ARProcessor_h__\n\nclass ARProcessor {\n\n};\n\n#endif // ARProcessor_h__"
  },
  {
    "path": "SoA/AmbienceLibrary.cpp",
    "content": "#include \"stdafx.h\"\n#include \"AmbienceLibrary.h\"\n\nvoid AmbienceLibrary::addTrack(const nString& list, const nString& name, const vpath& file) {\n    m_lists[list][name] = file;\n}\n\nconst AmbienceList& AmbienceLibrary::getTracks(const nString& name) const {\n    return m_lists.at(name);\n}\nAmbienceLibrary::Track AmbienceLibrary::getTrack(const nString& list, Random& rGen) const {\n    const AmbienceList& tracks = getTracks(list);\n\n    ui32 trackNum = (ui32)(rGen.genMT() * tracks.size()) % tracks.size();\n    printf(\"Chose track %d out of %zd in %s\\n\", trackNum + 1, tracks.size(), list.c_str());\n    AmbienceList::const_iterator iter = tracks.cbegin();\n    while (trackNum != 0) {\n        iter++;\n        trackNum--;\n    }\n\n    return Track(iter->first, iter->second);\n}\n"
  },
  {
    "path": "SoA/AmbienceLibrary.h",
    "content": "///\n/// AmbienceLibrary.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Library of all ambience tracks\n///\n\n#pragma once\n\n#ifndef AmbienceLibrary_h__\n#define AmbienceLibrary_h__\n\n#include <Vorb/IO.h>\n#include <Vorb/Random.h>\n\ntypedef std::unordered_map<nString, vpath> AmbienceList; ///< List of tracks (name, file) for an ambience type\n\n/// Library of music tracks organized by ambience\nclass AmbienceLibrary {\npublic:\n    typedef std::pair<nString, vpath> Track; ///< A named music file\n\n    /// Add a track to the library\n    /// @param list: Ambience type\n    /// @param name: Name of the track\n    /// @param file: File for the track\n    void addTrack(const nString& list, const nString& name, const vpath& file);\n\n    /// Obtain a list of tracks for a certain type of ambience\n    /// @param name: Ambience type\n    /// @return The list of tracks \n    const AmbienceList& getTracks(const nString& name) const;\n    /// Obtain a random track in an ambient list\n    /// @param list: Ambience type\n    /// @param rGen: Random generator\n    /// @return A random track that can be played\n    Track getTrack(const nString& list, Random& rGen) const;\nprivate:\n    std::unordered_map<nString, AmbienceList> m_lists; ///< Lists of ambiences that may play\n};\n\n#endif // AmbienceLibrary_h__\n"
  },
  {
    "path": "SoA/AmbiencePlayer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"AmbiencePlayer.h\"\n\n#include <Vorb/sound/SoundEngine.h>\n\n#include \"AmbienceLibrary.h\"\n\n#define AMBIENCE_PLAYER_DISPOSAL_RATE 2.0f\n\nvoid AmbiencePlayer::init(vsound::Engine* engine, const AmbienceLibrary* library) {\n    m_engine = engine;\n    m_lib = library;\n}\n\nvoid AmbiencePlayer::dispose() {\n    m_engine = nullptr;\n    m_lib = nullptr;\n}\n\nvoid AmbiencePlayer::setToTrack(const nString& name, const f32& fadeTime) {\n    // Set current ambience\n    currentAmbience = name;\n\n    if (!currentAmbience.empty()) {\n        // Make one track come alive\n        auto track = m_streams.find(currentAmbience);\n        if (track != m_streams.end()) {\n            // Reset track to be alive\n            track->second.stream.setPeakTime(fadeTime);\n        } else {\n            // Add a new stream\n            SoundStream stream;\n            stream.stream.setPeakTime(fadeTime);\n            m_streams[name] = stream;\n        }\n    }\n\n    // Make all other tracks fade away\n    for (auto& kvp : m_streams) {\n        if (kvp.first != currentAmbience) {\n            kvp.second.stream.setDeathTime(fadeTime);\n        }\n    }\n}\n\nvoid AmbiencePlayer::update(const f32& dt) {\n    if (!m_engine || !m_lib) return;\n\n    m_timerDisposal += dt;\n\n    // Update volumes if necessary\n    for (auto& kvp : m_streams) {\n        SoundStream& stream = kvp.second;\n        bool soundChanged = stream.stream.update(dt);\n\n        if (stream.stream.isAlive()) {\n            if (!stream.resource.isNull() && !stream.instance.isPlaying()) {\n                // Delete a finished track\n                m_engine->freeSound(stream.resource);\n            }\n\n            if (!stream.stream.isDying() && stream.resource.isNull()) {\n                // Get a new track\n                AmbienceLibrary::Track track = m_lib->getTrack(currentAmbience, m_rand);\n                currentTrack = track.first;\n\n                // Load and play the track\n                stream.resource = m_engine->loadSound(track.second, false, true);\n                stream.instance = m_engine->createInstance(stream.resource);\n                stream.instance.setLooped(false);\n                stream.instance.setVolume(stream.stream.getVolume() * m_volume);\n                stream.instance.play();\n            }\n\n            // Update volume\n            if (soundChanged) {\n                stream.instance.setVolume(stream.stream.getVolume() * m_volume);\n            }\n        }\n    }\n\n    // Dispose of old streams\n    if (m_timerDisposal > AMBIENCE_PLAYER_DISPOSAL_RATE) {\n        m_timerDisposal = 0.0f;\n\n        StreamMap updated;\n        for (auto& kvp : m_streams) {\n            if (kvp.second.stream.isAlive()) {\n                updated[kvp.first] = kvp.second;\n            } else {\n                if (!kvp.second.resource.isNull()) {\n                    m_engine->freeSound(kvp.second.resource);\n                }\n            }\n        }\n        m_streams.swap(updated);\n    }\n}\n\nvoid AmbiencePlayer::setVolume(f32 volume) {\n    m_volume = volume;\n    // Update volumes if necessary\n    for (auto& kvp : m_streams) {\n        SoundStream& stream = kvp.second;\n\n        if (stream.stream.isAlive()) {\n            stream.instance.setVolume(stream.stream.getVolume() * m_volume);\n        }\n    }\n}"
  },
  {
    "path": "SoA/AmbiencePlayer.h",
    "content": "///\n/// AmbiencePlayer.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Plays ambience tracks with cross-fading\n///\n\n#pragma once\n\n#ifndef AmbiencePlayer_h__\n#define AmbiencePlayer_h__\n\n#include <Vorb/Random.h>\n#include <Vorb/sound/SoundInstance.h>\n#include <Vorb/sound/SoundResource.h>\n#include <Vorb/VorbPreDecl.inl>\n\n#include \"AmbienceStream.h\"\n\nDECL_VSOUND(class Engine)\nclass AmbienceLibrary;\n\n/// Mixes ambient music for a game\n/// TODO: Make this thread-safe and put it on another thread with begin/end\nclass AmbiencePlayer {\npublic:\n    /// Setup all player references\n    /// @param engine: Sound engine that will be used by this player\n    /// @param library: Reference to library of ambient songs\n    void init(vsound::Engine* engine, const AmbienceLibrary* library);\n    /// Destroy all streams held by the player\n    void dispose();\n\n    /// Play a new mix of ambient music\n    /// @param name: Name of the ambience (that must be found in the library) or \"\" to stop all music\n    /// @param fadeTime: Amount of time until this stream becomes dominant\n    void setToTrack(const nString& name, UNIT_SPACE(SECONDS) const f32& fadeTime);\n\n    /// Update streams, loading in music tracks as necessary\n    /// @param dt: Elapsed time since the last update\n    /// TODO: return volume-change bool to allow intelligent sleeping\n    void update(UNIT_SPACE(SECONDS) const f32& dt);\n\n    const f32& getVolume() const { return m_volume; }\n    void setVolume(f32 volume);\nprivate:\n    /// A stream with a controller and sound information\n    struct SoundStream {\n    public:\n        AmbienceStream stream; ///< Stream controller\n        vsound::Resource resource; ///< Sound's resource data\n        vsound::Instance instance; ///< Playing sound handle\n    };\n\n    typedef std::unordered_map<nString, SoundStream> StreamMap;\n\n    UNIT_SPACE(SECONDS) f32 m_timerDisposal = 0.0f; ///< Time until dead streams are destroyed\n    vsound::Engine* m_engine = nullptr; ///< Reference to the sound engine\n    const AmbienceLibrary* m_lib = nullptr; ///< Reference to library of ambient sounds\n    StreamMap m_streams; ///< Currently playing ambience streams\n    Random m_rand; ///< Random number generator\n\n    f32 m_volume = 1.0f;\n    nString currentAmbience = \"\"; ///< Current ambience type\n    nString currentTrack = \"\"; ///< Currently playing track in the ambience stream\n};\n\n#endif // AmbiencePlayer_h__\n"
  },
  {
    "path": "SoA/AmbienceStream.cpp",
    "content": "#include \"stdafx.h\"\n#include \"AmbienceStream.h\"\n\nconst f32& AmbienceStream::getVolume() const {\n    return m_ratio;\n}\n\nbool AmbienceStream::isAlive() const {\n    return m_ratio > 0.0f || m_change > 0.0f;\n}\nbool AmbienceStream::isDying() const {\n    return m_change < 0.0f;\n}\n\nvoid AmbienceStream::setDeathTime(const f32& seconds) {\n    m_change = -m_ratio / seconds;\n}\nvoid AmbienceStream::setPeakTime(const f32& seconds) {\n    m_change = (1.0f - m_ratio) / seconds;\n}\n\nbool AmbienceStream::update(const f32& dt) {\n    if (m_change == 0.0f) return false;\n\n    m_ratio += m_change * dt;\n    if (m_change > 0.0f) {\n        if (m_ratio >= 1.0f) {\n            m_ratio = 1.0f;\n            m_change = 0.0f;\n        }\n    } else {\n        if (m_ratio <= 0.0f) {\n            m_ratio = 0.0f;\n            m_change = 0.0f;\n        }\n    }\n    return true;\n}\n"
  },
  {
    "path": "SoA/AmbienceStream.h",
    "content": "///\n/// AmbienceStream.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// A stream of music created from a list of ambient music\n///\n\n#pragma once\n\n#ifndef AmbienceStream_h__\n#define AmbienceStream_h__\n\n#include \"Vorb/types.h\"\n/// Encapsulates a stream of ambient music\nclass AmbienceStream {\npublic:\n    /// @return The relative volume of the stream [0,1]\n    const f32& getVolume() const;\n    /// @return True if this stream is in a playing state\n    bool isAlive() const;\n    /// @return True if this stream is fading away\n    bool isDying() const;\n\n    /// Set this stream to fade away to nothingness\n    /// @param seconds: Time until this stream is dead\n    void setDeathTime(UNIT_SPACE(SECONDS) const f32& seconds);\n    /// Set this stream to come alive from its current state\n    /// @param seconds: Time until this stream is fully audible\n    void setPeakTime(UNIT_SPACE(SECONDS) const f32& seconds);\n\n    /// Update a stream of music\n    /// @param dt: Elapsed time\n    /// @return True if the volume changed\n    bool update(UNIT_SPACE(SECONDS) const f32& dt);\nprivate:\n    f32 m_ratio = 0.0f; ///< The current liveliness level of the stream [0,1]\n    f32 m_change = 0.0f; ///< The rate of change of the ratio per second\n};\n\n#endif // AmbienceStream_h__\n"
  },
  {
    "path": "SoA/Animation.h",
    "content": "#pragma once\n\n#ifndef Animation_h_\n#define Animation_h_\n\n#include <Vorb/graphics/Texture.h>\n\nstruct Animation {\n    Animation() : fadeOutBegin(INT_MAX) {}\n    int duration;\n    int fadeOutBegin;\n    int repetitions;\n    int xFrames;\n    int yFrames;\n    int frames;\n    vg::Texture texture;\n};\n\n#endif // Animation_h_"
  },
  {
    "path": "SoA/App.cpp",
    "content": "#include \"stdafx.h\"\n#include \"App.h\"\n\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/ui/ScreenList.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/sound/SoundEngine.h>\n\n#include \"ChunkMeshManager.h\"\n#include \"CommonState.h\"\n#include \"DebugRenderer.h\"\n#include \"DevScreen.h\"\n#include \"GameManager.h\"\n#include \"GameplayLoadScreen.h\"\n#include \"GamePlayScreen.h\"\n#include \"InitScreen.h\"\n#include \"MainMenuLoadScreen.h\"\n#include \"MainMenuScreen.h\"\n#include \"SoaEngine.h\"\n#include \"SoaOptions.h\"\n#include \"SoAState.h\"\n#include \"SpaceSystem.h\"\n#include \"TestBiomeScreen.h\"\n#include \"TestBlockViewScreen.h\"\n#include \"TestConnectedTextureScreen.h\"\n#include \"TestConsoleScreen.h\"\n#include \"TestDeferredScreen.h\"\n#include \"TestDisplacementMappingScreen.h\"\n#include \"TestGasGiantScreen.h\"\n#include \"TestMappingScreen.h\"\n#include \"TestNewBlockAPIScreen.h\"\n#include \"TestNoiseScreen.h\"\n#include \"TestPlanetGenScreen.h\"\n#include \"TestScriptScreen.h\"\n#include \"TestStarScreen.h\"\n#include \"TestUIScreen.h\"\n#include \"TestVoxelModelScreen.h\"\n\nvoid App::addScreens() {\n    scrInit = new InitScreen(this);  \n    scrMainMenu = new MainMenuScreen(this, &state);\n    scrLoad = new MainMenuLoadScreen(this, &state, scrMainMenu);\n    scrGamePlay = new GameplayScreen(this, scrMainMenu);\n    scrGameplayLoad = new GameplayLoadScreen(this, &state, scrMainMenu, scrGamePlay);\n\n    m_screenList.addScreen(scrInit);\n    m_screenList.addScreen(scrLoad);\n    m_screenList.addScreen(scrMainMenu);\n    m_screenList.addScreen(scrGameplayLoad);\n    m_screenList.addScreen(scrGamePlay);\n\n    // Add development screen\n    scrDev = new DevScreen;\n    scrDev->addScreen(VKEY_RETURN, scrInit, \"Seed of Andromeda\");\n    m_screenList.addScreen(scrDev);\n\n    // Add test screens\n//    scrTests.push_back(new TestConsoleScreen);\n//    m_screenList.addScreen(scrTests.back());\n//    scrDev->addScreen(VKEY_C, scrTests.back(), \"TestConsoleScreen\");\n    scrTests.push_back(new TestMappingScreen);\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_M, scrTests.back(), \"TestMappingScreen\");\n    scrTests.push_back(new TestDeferredScreen);\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_D, scrTests.back(), \"TestDeferredScreen\");\n    scrTests.push_back(new TestBlockView);\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_B, scrTests.back(), \"TestBlockView\");\n    scrTests.push_back(new TestGasGiantScreen);\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_G, scrTests.back(), \"TestGasGiantScreen\");\n    scrTests.push_back(new TestScriptScreen(this, &state));\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_W, scrTests.back(), \"TestScriptScreen\");\n    scrTests.push_back(new TestStarScreen(this));\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_S, scrTests.back(), \"TestStarScreen\");\n    scrTests.push_back(new TestVoxelModelScreen(this));\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_V, scrTests.back(), \"TestVoxelModelScreen\");\n    scrTests.push_back(new TestDisplacementMappingScreen);\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_P, scrTests.back(), \"TestDisplacementMappingScreen\");\n    scrTests.push_back(new TestNoiseScreen(this));\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_N, scrTests.back(), \"TestNoiseScreen\");\n//    scrTests.push_back(new TestNewBlockAPIScreen);\n//    m_screenList.addScreen(scrTests.back());\n//    scrDev->addScreen(VKEY_A, scrTests.back(), \"TestNewBlockAPIScreen\");\n    scrTests.push_back(new TestPlanetGenScreen);\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_O, scrTests.back(), \"TestPlanetGenScreen\");\n    scrTests.push_back(new TestConnectedTextureScreen(this, &state));\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_T, scrTests.back(), \"TestConnectedTextureScreen\");\n    scrTests.push_back(new TestBiomeScreen(this, &state));\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_Z, scrTests.back(), \"TestBiomeScreen\");\n    scrTests.push_back(new TestUIScreen(this, &state));\n    m_screenList.addScreen(scrTests.back());\n    scrDev->addScreen(VKEY_U, scrTests.back(), \"TestUIScreen\");\n\n    // Uncomment to start from dev screen for testing other screens\n#define START_AT_DEV_SCREEN\n#ifdef START_AT_DEV_SCREEN\n    m_screenList.setScreen(scrDev->getIndex());\n#else\n    m_screenList.setScreen(scrInit->getIndex());\n#endif\n}\n\nvoid App::onInit() {\n    state.state = new SoaState;\n    state.window = &m_window;\n    state.soundEngine = new vsound::Engine;\n    state.soundEngine->init();\n\n    // Load the game options\n    SoaEngine::initOptions(soaOptions);\n\n    // Set the window options\n    soaOptions.get(OPT_FULLSCREEN).value.b = m_window.isFullscreen();\n    soaOptions.get(OPT_BORDERLESS).value.b = m_window.isBorderless();\n    soaOptions.get(OPT_SCREEN_WIDTH).value.i = m_window.getWidth();\n    soaOptions.get(OPT_SCREEN_HEIGHT).value.i = m_window.getHeight();\n    soaOptions.get(OPT_VSYNC).value.i = (m_window.getSwapInterval() == vui::GameSwapInterval::V_SYNC);\n\n    // Load the options from file\n    SoaEngine::optionsController.loadOptions();\n\n    vg::SamplerState::initPredefined();\n}\n\nvoid App::onExit() {\n    // Delete cache if it exists\n\n    vg::SpriteBatch::disposeProgram();\n}\n\nApp::~App() {\n    delete scrInit;\n    delete scrLoad;\n    delete scrMainMenu;\n    delete scrGamePlay;\n    delete scrDev;\n}"
  },
  {
    "path": "SoA/App.h",
    "content": "#pragma once\n\n#ifndef App_h_\n#define App_h_\n\n#include <Vorb/ui/MainGame.h>\n#include \"SoaOptions.h\"\n#include \"CommonState.h\"\n\nclass DevScreen;\nclass GameplayLoadScreen;\nclass GameplayScreen;\nclass InitScreen;\nclass MainMenuLoadScreen;\nclass MainMenuScreen;\nclass TexturePackLoader;\n\nclass App : public vui::MainGame {\npublic:\n    virtual ~App();\n\n    virtual void addScreens();\n    virtual void onInit();\n    virtual void onExit();\n\n    // Accessible Pointers To Screens\n    InitScreen* scrInit = nullptr;\n    MainMenuLoadScreen* scrLoad = nullptr;\n    MainMenuScreen* scrMainMenu = nullptr;\n    GameplayLoadScreen* scrGameplayLoad = nullptr;\n    GameplayScreen* scrGamePlay = nullptr;\n\n    DevScreen* scrDev = nullptr;\n    std::vector<vui::IGameScreen*> scrTests;\n\n    CommonState state;\n};\n\n#endif // App_h_\n"
  },
  {
    "path": "SoA/AtmosphereComponentRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"AtmosphereComponentRenderer.h\"\n\n#include \"SpaceSystem.h\"\n#include \"RenderUtils.h\"\n#include \"soaUtils.h\"\n#include \"ShaderLoader.h\"\n\n#include <Vorb/MeshGenerators.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/RasterizerState.h>\n#include <Vorb/graphics/ShaderManager.h>\n#include <Vorb/math/VorbMath.hpp>\n\n#define ICOSPHERE_SUBDIVISIONS 5\n\nAtmosphereComponentRenderer::~AtmosphereComponentRenderer() {\n    dispose();\n}\n\nvoid AtmosphereComponentRenderer::initGL() {\n    if (!m_program.isCreated()) {\n        m_program = ShaderLoader::createProgramFromFile(\"Shaders/AtmosphereShading/Sky.vert\",\n                                                        \"Shaders/AtmosphereShading/Sky.frag\");\n    }\n    if (!m_icoVbo) buildMesh();\n}\n\nvoid AtmosphereComponentRenderer::draw(const AtmosphereComponent& aCmp,\n                                       const f32m4& VP,\n                                       const f32v3& relCamPos,\n                                       const f32v3& lightDir,\n                                       const f32 zCoef,\n                                       const SpaceLightComponent* spComponent VORB_MAYBE_UNUSED) {\n    m_program.use();\n\n    // Set up matrix\n    f32m4 WVP(1.0);\n    setMatrixScale(WVP, f32v3(aCmp.radius, aCmp.radius * (1.0 - aCmp.oblateness), aCmp.radius));\n    setMatrixTranslation(WVP, -relCamPos);\n    WVP = VP * WVP;\n\n    f32 camHeight = glm::length(relCamPos);\n    f32 camHeight2 = camHeight * camHeight;\n\n    // Upload uniforms\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, GL_FALSE, &WVP[0][0]);\n    glUniform3fv(m_program.getUniform(\"unCameraPos\"), 1, &relCamPos[0]);\n    glUniform3fv(m_program.getUniform(\"unLightDirWorld\"), 1, &lightDir[0]);\n    glUniform3fv(m_program.getUniform(\"unInvWavelength\"), 1, &aCmp.invWavelength4[0]);\n    glUniform1f(m_program.getUniform(\"unCameraHeight2\"), camHeight2);\n    glUniform1f(m_program.getUniform(\"unOuterRadius\"), aCmp.radius);\n    glUniform1f(m_program.getUniform(\"unOuterRadius2\"), aCmp.radius * aCmp.radius);\n    glUniform1f(m_program.getUniform(\"unInnerRadius\"), aCmp.planetRadius);\n    glUniform1f(m_program.getUniform(\"unKrESun\"), aCmp.kr * aCmp.esun);\n    glUniform1f(m_program.getUniform(\"unKmESun\"), aCmp.km * aCmp.esun);\n    glUniform1f(m_program.getUniform(\"unKr4PI\"), (f32)(aCmp.kr * M_4_PI));\n    glUniform1f(m_program.getUniform(\"unKm4PI\"), (f32)(aCmp.km * M_4_PI));\n    float scale = 1.0f / (aCmp.radius - aCmp.planetRadius);\n    glUniform1f(m_program.getUniform(\"unScale\"), scale);\n    glUniform1f(m_program.getUniform(\"unScaleDepth\"), aCmp.scaleDepth);\n    glUniform1f(m_program.getUniform(\"unScaleOverScaleDepth\"), scale / aCmp.scaleDepth);\n    glUniform1i(m_program.getUniform(\"unNumSamples\"), 3);\n    glUniform1f(m_program.getUniform(\"unNumSamplesF\"), 3.0f);\n    glUniform1f(m_program.getUniform(\"unG\"), aCmp.g);\n    glUniform1f(m_program.getUniform(\"unG2\"), aCmp.g * aCmp.g);\n    // For logarithmic Z buffer\n    glUniform1f(m_program.getUniform(\"unZCoef\"), zCoef);\n\n    // Bind VAO\n    glBindVertexArray(m_vao);\n   \n    // Render\n    glDepthMask(GL_FALSE);\n    vg::RasterizerState::CULL_COUNTER_CLOCKWISE.set();\n    glDrawElements(GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, 0);\n    glDepthMask(GL_TRUE);\n    vg::RasterizerState::CULL_CLOCKWISE.set();\n\n    glBindVertexArray(0);\n    m_program.unuse(); \n}\n\nvoid AtmosphereComponentRenderer::dispose() {\n    if (m_program.isCreated()) m_program.dispose();\n    if (m_icoVbo) vg::GpuMemory::freeBuffer(m_icoVbo);\n    if (m_icoIbo) vg::GpuMemory::freeBuffer(m_icoIbo);\n    if (m_vao) glDeleteVertexArrays(1, &m_vao);\n}\n\nvoid AtmosphereComponentRenderer::buildMesh() {\n    std::vector<ui32> indices;\n    std::vector<f32v3> positions;\n\n    // TODO(Ben): Optimize with LOD for far viewing\n    vmesh::generateIcosphereMesh(ICOSPHERE_SUBDIVISIONS, indices, positions);\n    m_numIndices = indices.size();\n\n    glGenVertexArrays(1, &m_vao);\n    glBindVertexArray(m_vao);\n\n    vg::GpuMemory::createBuffer(m_icoVbo);\n    vg::GpuMemory::createBuffer(m_icoIbo);\n\n    vg::GpuMemory::bindBuffer(m_icoVbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_icoVbo, vg::BufferTarget::ARRAY_BUFFER, positions.size() * sizeof(f32v3),\n                                    positions.data(), vg::BufferUsageHint::STATIC_DRAW);\n\n    vg::GpuMemory::bindBuffer(m_icoIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_icoIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(ui32),\n                                    indices.data(), vg::BufferUsageHint::STATIC_DRAW);\n\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);\n    m_program.enableVertexAttribArrays();\n\n    glBindVertexArray(0);\n}"
  },
  {
    "path": "SoA/AtmosphereComponentRenderer.h",
    "content": "///\n/// AtmosphereComponentRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Mar 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renders atmosphere components\n///\n\n#pragma once\n\n#ifndef AtmosphereComponentRenderer_h__\n#define AtmosphereComponentRenderer_h__\n\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/ecs/ComponentTable.hpp>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/graphics/GLProgram.h>\n\nstruct AtmosphereComponent;\nstruct SpaceLightComponent;\n\nclass AtmosphereComponentRenderer {\npublic:\n    ~AtmosphereComponentRenderer();\n\n    void initGL();\n    void draw(const AtmosphereComponent& aCmp,\n              const f32m4& VP,\n              const f32v3& relCamPos,\n              const f32v3& lightDir,\n              const f32 zCoef,\n              const SpaceLightComponent* spComponent);\n    void dispose();\nprivate:\n    void buildMesh();\n\n    vg::GLProgram m_program;\n    VGBuffer m_icoVbo = 0;\n    VGIndexBuffer m_icoIbo = 0;\n    VGVertexArray m_vao = 0;\n    int m_numIndices = 0;\n};\n\n#endif // AtmosphereComponentRenderer_h__\n\n"
  },
  {
    "path": "SoA/AxisRotationComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"AxisRotationComponentUpdater.h\"\n\n#include \"SpaceSystem.h\"\n#include \"Constants.h\"\n\nvoid AxisRotationComponentUpdater::update(SpaceSystem* spaceSystem, f64 time) {\n    for (auto& it : spaceSystem->axisRotation) {\n        auto& cmp = it.second;\n        // Calculate rotation\n        if (cmp.period) {\n            cmp.currentRotation = (time / cmp.period) * 2.0 * M_PI;\n        }\n\n        // Calculate the axis rotation quat\n        f64v3 eulerAngles(0, -cmp.currentRotation, 0);\n        f64q rotationQuat = f64q(eulerAngles);\n\n        // Calculate total orientation\n        cmp.currentOrientation = cmp.axisOrientation * rotationQuat;\n        cmp.invCurrentOrientation = glm::inverse(cmp.currentOrientation);\n    }\n}\n"
  },
  {
    "path": "SoA/AxisRotationComponentUpdater.h",
    "content": "///\n/// AxisRotationComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates AxisRotationComponents\n///\n\n#pragma once\n\n#ifndef AxisRotationComponentUpdater_h__\n#define AxisRotationComponentUpdater_h__\n\n#include \"Vorb/types.h\"\n\nclass SpaceSystem;\n\nclass AxisRotationComponentUpdater {\npublic:\n    /// Updates the components\n    /// @param spaceSystem: The ECS space system\n    /// @param time: Time in seconds\n    void update(SpaceSystem* spaceSystem, f64 time);\n};\n\n#endif // AxisRotationComponentUpdater_h__"
  },
  {
    "path": "SoA/Biome.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Biome.h\"\n\nKEG_TYPE_DEF_SAME_NAME(BiomeFloraKegProperties, kt) {\n    using namespace keg;\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeFloraKegProperties, id, STRING);\n    kt.addValue(\"chance\", Value::custom(offsetof(BiomeFloraKegProperties, chance), \"NoiseBase\", false));\n}\n\nKEG_TYPE_DEF_SAME_NAME(BiomeTreeKegProperties, kt) {\n    using namespace keg;\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeTreeKegProperties, id, STRING);\n    kt.addValue(\"chance\", Value::custom(offsetof(BiomeTreeKegProperties, chance), \"NoiseBase\", false));\n}\n"
  },
  {
    "path": "SoA/Biome.h",
    "content": "///\n/// Biome.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 30 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Provides the biome implementation.\n///\n#pragma once\n\n#ifndef Biome_h__\n#define Biome_h__\n\n#include \"Noise.h\"\n#include \"Flora.h\"\n\nstruct PlanetGenData;\n\n// TODO(Ben): Also support L-system trees.\nstruct BiomeTree {\n    NoiseBase chance;\n    NTreeType* data = nullptr;\n    FloraID id = FLORA_ID_NONE;\n};\n\nstruct BiomeFloraKegProperties {\n    NoiseBase chance;\n    nString id;\n};\nKEG_TYPE_DECL(BiomeFloraKegProperties);\n\nstruct BiomeTreeKegProperties {\n    NoiseBase chance;\n    nString id;\n};\nKEG_TYPE_DECL(BiomeTreeKegProperties);\n\n// Unique flora instance\nstruct BiomeFlora {\n    NoiseBase chance;\n    FloraType* data = nullptr;\n    FloraID id = FLORA_ID_NONE;\n};\n\nstruct BlockLayer {\n    ui32 start;\n    ui32 width;\n    ui16 block = 0;\n    ui16 surfaceTransform = 0; ///< This block is used on surface\n};\n\n#define BIOME_MAP_WIDTH 256\n\ntypedef nString BiomeID;\nstruct Biome;\n\nstruct BiomeInfluence {\n    BiomeInfluence() {};\n    BiomeInfluence(const Biome* b, f32 weight) : b(b), weight(weight) {}\n    const Biome* b;\n    f32 weight;\n\n    bool operator<(const BiomeInfluence& rhs) const {\n        // Ignore weight on purpose. Only one BiomeInfluence per set or map!\n        return b < rhs.b;\n    }\n};\n\n// TODO(Ben): Make the memory one contiguous block\ntypedef std::vector<std::vector<BiomeInfluence>> BiomeInfluenceMap;\n\n// TODO(Ben): Optimize the cache\nstruct Biome {\n    Biome():id(\"default\"), displayName(\"Default\"), mapColor(255, 255, 255), genData(nullptr){}\n\n    BiomeID id;\n    nString displayName;\n    ColorRGB8 mapColor; ///< For debugging and lookups\n    std::vector<BlockLayer> blockLayers; ///< Overrides base layers\n    std::vector<Biome*> children;\n    std::vector<BiomeFlora> flora;\n    std::vector<BiomeTree> trees;\n    NoiseBase childNoise; ///< For sub biome determination\n    NoiseBase terrainNoise; ///< Modifies terrain directly\n    // Only applies to base biomes\n    f64v2 heightRange;\n    f64v2 heightScale;\n    f64v2 noiseRange;\n    f64v2 noiseScale;\n    const PlanetGenData* genData;\n};\n\nstatic const Biome DEFAULT_BIOME;\n\n#endif // Biome_h__\n"
  },
  {
    "path": "SoA/BlendState.h",
    "content": "#pragma once\n\nenum BlendEquationMode {\n    BLEND_EQUATION_MODE_FUNC_ADD = GL_FUNC_ADD,\n    BLEND_EQUATION_MODE_FUNC_REVERSE_SUBTRACT = GL_FUNC_REVERSE_SUBTRACT,\n    BLEND_EQUATION_MODE_FUNC_SUBTRACT = GL_FUNC_SUBTRACT,\n    BLEND_EQUATION_MODE_MAX = GL_MAX,\n    BLEND_EQUATION_MODE_MIN = GL_MIN\n};\nenum BlendingFactorSrc {\n    BLENDING_FACTOR_SRC_CONSTANT_ALPHA = GL_CONSTANT_ALPHA,\n    BLENDING_FACTOR_SRC_CONSTANT_COLOR = GL_CONSTANT_COLOR,\n    BLENDING_FACTOR_SRC_DST_ALPHA = GL_DST_ALPHA,\n    BLENDING_FACTOR_SRC_DST_COLOR = GL_DST_COLOR,\n    BLENDING_FACTOR_SRC_ONE = GL_ONE,\n    BLENDING_FACTOR_SRC_ONE_MINUS_CONSTANT_ALPHA = GL_ONE_MINUS_CONSTANT_ALPHA,\n    BLENDING_FACTOR_SRC_ONE_MINUS_CONSTANT_COLOR = GL_ONE_MINUS_CONSTANT_COLOR,\n    BLENDING_FACTOR_SRC_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA,\n    BLENDING_FACTOR_SRC_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR,\n    BLENDING_FACTOR_SRC_ONE_MINUS_SRC_1_ALPHA = GL_ONE_MINUS_SRC1_ALPHA,\n    BLENDING_FACTOR_SRC_ONE_MINUS_SRC_1_COLOR = GL_ONE_MINUS_SRC1_COLOR,\n    BLENDING_FACTOR_SRC_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA,\n    BLENDING_FACTOR_SRC_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,\n    BLENDING_FACTOR_SRC_SRC_1_ALPHA = GL_SRC1_ALPHA,\n    BLENDING_FACTOR_SRC_SRC_1_COLOR = GL_SRC1_COLOR,\n    BLENDING_FACTOR_SRC_SRC_ALPHA = GL_SRC_ALPHA,\n    BLENDING_FACTOR_SRC_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE,\n    BLENDING_FACTOR_SRC_SRC_COLOR = GL_SRC_COLOR,\n    BLENDING_FACTOR_SRC_ZERO = GL_ZERO\n};\nenum BlendingFactorDest {\n    BLENDING_FACTOR_DEST_CONSTANT_ALPHA = GL_CONSTANT_ALPHA,\n    BLENDING_FACTOR_DEST_CONSTANT_COLOR = GL_CONSTANT_COLOR,\n    BLENDING_FACTOR_DEST_DST_ALPHA = GL_DST_ALPHA,\n    BLENDING_FACTOR_DEST_DST_COLOR = GL_DST_COLOR,\n    BLENDING_FACTOR_DEST_ONE = GL_ONE,\n    BLENDING_FACTOR_DEST_ONE_MINUS_CONSTANT_ALPHA = GL_ONE_MINUS_CONSTANT_ALPHA,\n    BLENDING_FACTOR_DEST_ONE_MINUS_CONSTANT_COLOR = GL_ONE_MINUS_CONSTANT_COLOR,\n    BLENDING_FACTOR_DEST_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA,\n    BLENDING_FACTOR_DEST_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR,\n    BLENDING_FACTOR_DEST_ONE_MINUS_SRC_1_ALPHA = GL_ONE_MINUS_SRC1_ALPHA,\n    BLENDING_FACTOR_DEST_ONE_MINUS_SRC_1_COLOR = GL_ONE_MINUS_SRC1_COLOR,\n    BLENDING_FACTOR_DEST_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA,\n    BLENDING_FACTOR_DEST_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR,\n    BLENDING_FACTOR_DEST_SRC_1_ALPHA = GL_SRC1_ALPHA,\n    BLENDING_FACTOR_DEST_SRC_1_COLOR = GL_SRC1_COLOR,\n    BLENDING_FACTOR_DEST_SRC_ALPHA = GL_SRC_ALPHA,\n    BLENDING_FACTOR_DEST_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE,\n    BLENDING_FACTOR_DEST_SRC_COLOR = GL_SRC_COLOR,\n    BLENDING_FACTOR_DEST_ZERO = GL_ZERO\n};\n\nclass BlendFunction {\npublic:\n    BlendFunction(BlendEquationMode bem, BlendingFactorSrc bfs, BlendingFactorDest bfd);\n\n    BlendEquationMode blendMode;\n    BlendingFactorSrc blendFactorSrc;\n    BlendingFactorDest blendFactorDest;\n};\n\n\nclass BlendState {\npublic:\n    BlendState(BlendFunction funcRGB, BlendFunction funcAlpha);\n\n    void set() const;\n\n    BlendFunction blendFuncRGB;\n    BlendFunction blendFuncAlpha;\n};"
  },
  {
    "path": "SoA/BlockData.cpp",
    "content": "#include \"stdafx.h\"\n#include \"BlockData.h\"\n\n#include \"BlockPack.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"SoaOptions.h\"\n#include \"ZipFile.h\"\n\nKEG_ENUM_DEF(BlockOcclusion, BlockOcclusion, e) {\n    e.addValue(\"none\", BlockOcclusion::NONE);\n    e.addValue(\"self\", BlockOcclusion::SELF);\n    // TODO(Ben): Temporary\n    e.addValue(\"selfOnly\", BlockOcclusion::SELF);\n    e.addValue(\"all\", BlockOcclusion::ALL);\n}\n\nKEG_TYPE_DEF_SAME_NAME(Block, kt) {\n    kt.addValue(\"ID\", keg::Value::basic(offsetof(Block, temp), keg::BasicType::I32));\n    kt.addValue(\"name\", keg::Value::basic(offsetof(Block, name), keg::BasicType::STRING));\n    kt.addValue(\"burnTransformID\", keg::Value::basic(offsetof(Block, burnTransformID), keg::BasicType::STRING));\n    kt.addValue(\"waveEffect\", keg::Value::basic(offsetof(Block, waveEffect), keg::BasicType::I16));\n    kt.addValue(\"lightColor\", keg::Value::basic(offsetof(Block, lightColor), keg::BasicType::UI8_V3));\n    kt.addValue(\"caPhysics\", keg::Value::basic(offsetof(Block, caFilePath), keg::BasicType::STRING));\n    kt.addValue(\"waterMeshLevel\", keg::Value::basic(offsetof(Block, waterMeshLevel), keg::BasicType::I16));\n    kt.addValue(\"floatingAction\", keg::Value::basic(offsetof(Block, floatingAction), keg::BasicType::I16));\n    kt.addValue(\"occlusion\", keg::Value::custom(offsetof(Block, occlude), \"BlockOcclusion\", true));\n    kt.addValue(\"spawnID\", keg::Value::basic(offsetof(Block, spawnerID), keg::BasicType::STRING));\n    kt.addValue(\"sinkID\", keg::Value::basic(offsetof(Block, sinkID), keg::BasicType::STRING));\n    kt.addValue(\"explosionRays\", keg::Value::basic(offsetof(Block, explosionRays), keg::BasicType::UI16));\n    kt.addValue(\"meshType\", keg::Value::custom(offsetof(Block, meshType), \"MeshType\", true));\n    kt.addValue(\"moveMod\", keg::Value::basic(offsetof(Block, moveMod), keg::BasicType::F32));\n    kt.addValue(\"explosionResistance\", keg::Value::basic(offsetof(Block, explosionResistance), keg::BasicType::F32));\n    kt.addValue(\"explosionPower\", keg::Value::basic(offsetof(Block, explosivePower), keg::BasicType::F32));\n    kt.addValue(\"flammability\", keg::Value::basic(offsetof(Block, flammability), keg::BasicType::F32));\n    kt.addValue(\"explosionPowerLoss\", keg::Value::basic(offsetof(Block, explosionPowerLoss), keg::BasicType::F32));\n    kt.addValue(\"lightColorFilter\", keg::Value::basic(offsetof(Block, colorFilter), keg::BasicType::F32_V3));\n    kt.addValue(\"emitter\", keg::Value::basic(offsetof(Block, emitterName), keg::BasicType::STRING));\n    kt.addValue(\"movesPowder\", keg::Value::basic(offsetof(Block, powderMove), keg::BasicType::BOOL));\n    kt.addValue(\"collide\", keg::Value::basic(offsetof(Block, collide), keg::BasicType::BOOL));\n    kt.addValue(\"waterBreak\", keg::Value::basic(offsetof(Block, waterBreak), keg::BasicType::BOOL));\n    kt.addValue(\"scatterSunRays\", keg::Value::basic(offsetof(Block, blockLight), keg::BasicType::BOOL));\n    kt.addValue(\"useable\", keg::Value::basic(offsetof(Block, useable), keg::BasicType::BOOL));\n    kt.addValue(\"allowsLight\", keg::Value::basic(offsetof(Block, allowLight), keg::BasicType::BOOL));\n    kt.addValue(\"crushable\", keg::Value::basic(offsetof(Block, isCrushable), keg::BasicType::BOOL));\n    kt.addValue(\"supportive\", keg::Value::basic(offsetof(Block, isSupportive), keg::BasicType::BOOL));\n}\n\n// TODO(Ben): LOL\nBlock::Block() : lightColor(0, 0, 0),\nemitterName(\"\"), \nemitterOnBreakName(\"\"), \nemitterRandomName(\"\"),\nemitter(nullptr),\nemitterOnBreak(nullptr),\nemitterRandom(nullptr) {\n    allowLight = false;\n    ID = 0;\n    name = particleTexName = \"\";\n    memset(textures, 0, sizeof(textures));\n    particleTex = 0;\n    collide = true;\n    occlude = BlockOcclusion::ALL;\n    meshType = MeshType::BLOCK;\n    waveEffect = 0;\n    explosionResistance = 1.0;\n    active = 0;\n    useable = 1;\n    blockLight = true;\n    waterMeshLevel = 0;\n    waterBreak = false;\n    isCrushable = false;\n    floatingAction = 1;\n    flammability = 0.0f;\n    isSupportive = true;\n    explosivePower = 0.0;\n    explosionPowerLoss = 0.0;\n    explosionRays = 0;\n    powderMove = true;\n    moveMod = 1.0f;\n    spawnerID = \"\";\n    sinkID = \"\";\n    colorFilter = f32v3(1.0f);\n}\n"
  },
  {
    "path": "SoA/BlockData.h",
    "content": "#pragma once\n#include \"stdafx.h\"\n\n#include <SDL2/SDL.h>\n#include <Vorb/io/Keg.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/voxel/VoxCommon.h>\n\n#include \"CAEngine.h\"\n#include \"ChunkMesh.h\"\n#include \"BlockTexture.h\"\n#include \"Constants.h\"\n#include \"Item.h\"\n\n#define GETFLAGS(a) ((a) >> 12)\n#define GETFLAG1(a) (((a) & 0x8000) >> 15)\n#define GETFLAG2(a) (((a) & 0x4000) >> 14)\n#define GETFLAG3(a) (((a) & 0x2000) >> 13)\n#define GETFLAG4(a) (((a) & 0x1000) >> 12)\n#define GETBLOCKID(a) (((a) & 0x0FFF))\n#define SETFLAGS(a, b) ((a) = ((a) | ((b) << 12)))\n\nenum class BlockOcclusion {\n    NONE,\n    ALL,\n    SELF,\n    SELF_ONLY\n};\nKEG_ENUM_DECL(BlockOcclusion);\n\nclass BlockTextureFaces {\npublic:\n    union {\n        ui32 array[6]; /// Access 6-sided block textures as an array\n        class {\n        public:\n            ui32 nx;  /// Negative x-axis texture\n            ui32 px;  /// Positive x-axis texture\n            ui32 ny;  /// Negative y-axis texture\n            ui32 py;  /// Positive y-axis texture\n            ui32 nz;  /// Negative z-axis texture\n            ui32 pz;  /// Positive z-axis texture\n        }; /// Textures named in cardinal convention\n    };\n    \n    ui32& operator[] (const i32& i) {\n        return array[i];\n    }\n    const ui32& operator[] (const i32& i) const {\n        return array[i];\n    }\n};\n\ntypedef nString BlockIdentifier; ///< Unique identifier key for blocks\n\ntypedef ui16 BlockID;\n\nclass Block\n{\npublic:\n    Block();\n\n    void SetAvgTexColors();\n\n    i32 temp;\n\n    BlockIdentifier sID;\n    nString name;\n    BlockID ID;\n    nString burnTransformID;\n    i16 waveEffect;\n    ui16 lightColorPacked; /// 5 bit RGB light color packed into a ui16\n    i16 waterMeshLevel;\n    i16 floatingAction;\n    nString spawnerID;\n    nString sinkID;\n    ui16 explosionRays;\n    ui16 floraHeight = 0;\n    ui16 liquidStartID = 0;\n    ui16 liquidLevels = 0;\n\n    BlockOcclusion occlude;\n\n    MeshType meshType;\n\n    GLfloat moveMod;\n    GLfloat explosionResistance;\n    GLfloat explosivePower;\n    GLfloat flammability;\n    GLfloat explosionPowerLoss;\n    f32v3 colorFilter;\n\n    int caIndex = -1;\n    CAAlgorithm caAlg = CAAlgorithm::NONE;\n    nString caFilePath = \"\";\n\n    ColorRGB8 lightColor;\n    ui8 particleTex;\n    bool powderMove;\n    bool collide;\n    bool waterBreak;\n    bool blockLight;\n    bool useable;\n    bool allowLight;\n    bool isCrushable;\n    bool isSupportive;\n    bool active;\n\n    union {\n        struct {\n            BlockTexture* textureLeft;\n            BlockTexture* textureRight;\n            BlockTexture* textureBottom;\n            BlockTexture* textureTop;\n            BlockTexture* textureBack;\n            BlockTexture* textureFront;\n        };\n        BlockTexture* textures[6];\n    };\n\n    // TODO(Ben): NOPE\n    //                      ... but why?\n    nString particleTexName;\n    nString emitterName, emitterOnBreakName, emitterRandomName;\n    class ParticleEmitter *emitter, *emitterOnBreak, *emitterRandom;\n\n    std::vector <ColorRGB8> altColors;\n};\nKEG_TYPE_DECL(Block);\n\n"
  },
  {
    "path": "SoA/BlockLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"BlockLoader.h\"\n\n#include <Vorb/io/IOManager.h>\n#include <Vorb/io/Keg.h>\n\n#include \"BlockPack.h\"\n#include \"Chunk.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"VoxelBits.h\"\n\n#define BLOCK_MAPPING_PATH \"BlockMapping.ini\"\n#define BLOCK_DATA_PATH \"BlockData.yml\"\n#define BINARY_CACHE_PATH \"BlockCache.bin\"\n\nbool BlockLoader::loadBlocks(const vio::IOManager& iom, BlockPack* pack) {\n    // Load existing mapping if there is one\n    tryLoadMapping(iom, BLOCK_MAPPING_PATH, pack);\n\n    // Check for binary cache\n    vio::Path binPath;\n    bool useCache = false;\n    if (iom.resolvePath(BINARY_CACHE_PATH, binPath)) {\n        vio::Path dataPath;\n        if (!iom.resolvePath(BLOCK_DATA_PATH, dataPath)) return false;\n        if (binPath.getLastModTime() >= dataPath.getLastModTime()) {\n            useCache = true;\n        }\n    }\n   \n    // Clear CA physics cache\n    CaPhysicsType::clearTypes();\n\n    GameBlockPostProcess bpp(&iom, &CaPhysicsType::typesCache);\n    pack->onBlockAddition += bpp.del;\n    if (useCache) {\n        if (!BlockLoader::loadBinary(iom, BINARY_CACHE_PATH, pack)) {\n            printf(\"Failed to load binary cache %s\\n\", BINARY_CACHE_PATH);\n            if (!BlockLoader::load(iom, BLOCK_DATA_PATH, pack)) {\n                pack->onBlockAddition -= bpp.del;\n                return false;\n            }\n        }\n    } else {\n        if (!BlockLoader::load(iom, BLOCK_DATA_PATH, pack)) {\n            pack->onBlockAddition -= bpp.del;\n            return false;\n        }\n    }\n    pack->onBlockAddition -= bpp.del;\n\n    saveMapping(iom, BLOCK_MAPPING_PATH, pack);\n    if (!useCache) {\n   //     saveBinary(iom, BINARY_CACHE_PATH, pack);\n    }\n\n    return true;\n}\n\n// Conditional keg write\n#define COND_WRITE_KEG(key, var) if (b.var != d.var) { writer.push(keg::WriterParam::KEY) << nString(key); writer.push(keg::WriterParam::VALUE) << b.var; } \n\nbool BlockLoader::saveBlocks(const nString& filePath, BlockPack* pack) {\n    // Open the portal to Hell\n    std::ofstream file(filePath);\n    if (file.fail()) return false;\n\n    BlockPack& blocks = *pack;\n\n    std::map<nString, const Block*> sortMap;\n    const std::vector<Block>& blockList = blocks.getBlockList();\n    for (size_t i = 0; i < blockList.size(); i++) {\n        const Block& b = blockList[i];\n        if (b.active) {\n            sortMap[b.sID] = &b;\n        }\n    }\n    // Default block\n    Block d;\n    // Emit data\n    keg::YAMLWriter writer;\n    writer.push(keg::WriterParam::BEGIN_MAP);\n    for (auto& it : sortMap) {\n        const Block& b = *it.second;\n\n        // Write the block name first\n        writer.push(keg::WriterParam::KEY) << b.sID;\n        // Write the block data now\n        writer.push(keg::WriterParam::VALUE);\n        writer.push(keg::WriterParam::BEGIN_MAP);\n\n        COND_WRITE_KEG(\"allowsLight\", allowLight);\n        COND_WRITE_KEG(\"collide\", collide);\n        COND_WRITE_KEG(\"crushable\", isCrushable);\n        COND_WRITE_KEG(\"explosionPower\", explosivePower);\n        COND_WRITE_KEG(\"explosionPowerLoss\", explosionPowerLoss);\n        COND_WRITE_KEG(\"explosionRays\", explosionRays);\n        COND_WRITE_KEG(\"explosionResistance\", explosionResistance);\n        COND_WRITE_KEG(\"flammability\", flammability);\n        COND_WRITE_KEG(\"floatingAction\", floatingAction);\n        if (b.colorFilter != d.colorFilter) { writer.push(keg::WriterParam::KEY) << nString(\"lightColorFilter\"); writer.push(keg::WriterParam::VALUE) << keg::kegf32v3(b.colorFilter); }\n        if (b.meshType != d.meshType) {\n            writer.push(keg::WriterParam::KEY) << nString(\"meshType\");\n            switch (b.meshType) {\n                case MeshType::NONE:\n                    writer.push(keg::WriterParam::VALUE) << nString(\"none\");\n                    break;\n                case MeshType::BLOCK:\n                    writer.push(keg::WriterParam::VALUE) << nString(\"cube\");\n                    break;\n                case MeshType::LEAVES:\n                    writer.push(keg::WriterParam::VALUE) << nString(\"leaves\");\n                    break;\n                case MeshType::TRIANGLE:\n                    writer.push(keg::WriterParam::VALUE) << nString(\"triangle\");\n                    break;\n                case MeshType::CROSSFLORA:\n                    writer.push(keg::WriterParam::VALUE) << nString(\"cross\");\n                    break;\n                case MeshType::LIQUID:\n                    writer.push(keg::WriterParam::VALUE) << nString(\"liquid\");\n                    break;\n                case MeshType::FLAT:\n                    writer.push(keg::WriterParam::VALUE) << nString(\"flat\");\n                    break;\n            }\n        }\n        COND_WRITE_KEG(\"moveMod\", moveMod);\n        COND_WRITE_KEG(\"name\", name);\n        switch (b.occlude) {\n            case BlockOcclusion::NONE:\n                writer.push(keg::WriterParam::KEY) << nString(\"occlusion\");\n                writer.push(keg::WriterParam::VALUE) << nString(\"none\");\n                break;\n            case BlockOcclusion::ALL:\n                writer.push(keg::WriterParam::KEY) << nString(\"occlusion\");\n                writer.push(keg::WriterParam::VALUE) << nString(\"all\");\n                break;\n            case BlockOcclusion::SELF:\n                writer.push(keg::WriterParam::KEY) << nString(\"occlusion\");\n                writer.push(keg::WriterParam::VALUE) << nString(\"self\");\n                break;\n            case BlockOcclusion::SELF_ONLY:\n                writer.push(keg::WriterParam::KEY) << nString(\"occlusion\");\n                writer.push(keg::WriterParam::VALUE) << nString(\"selfOnly\");\n                break;\n        }\n        COND_WRITE_KEG(\"sinkID\", sinkID);\n        COND_WRITE_KEG(\"spawnerID\", spawnerID);\n        COND_WRITE_KEG(\"supportive\", isSupportive);\n        COND_WRITE_KEG(\"waterBreak\", waterBreak);\n\n        //keg::write((ui8*)b, writer, keg::getGlobalEnvironment(), &KEG_GLOBAL_TYPE(Block));\n        writer.push(keg::WriterParam::END_MAP);\n        \n    }\n    writer.push(keg::WriterParam::END_MAP);\n\n    file << writer.c_str();\n    file.flush();\n    file.close();\n    return true;\n}\n\nbool BlockLoader::load(const vio::IOManager& iom, const cString filePath, BlockPack* pack) {\n    // Read file\n    nString data;\n    iom.readFileToString(filePath, data);\n    if (data.empty()) return false;\n\n    // Convert to YAML\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        context.reader.dispose();\n        return false;\n    }\n\n    // Load all block nodes\n    std::vector<Block> loadedBlocks;\n    auto f = makeFunctor([&] (Sender, const nString& key, keg::Node value) {\n        // Add a block\n        loadedBlocks.emplace_back();\n        Block& b = loadedBlocks.back();\n\n        // Set sID to key\n        b.sID = key;\n        \n        // Load data\n        keg::parse((ui8*)&b, value, context, &KEG_GLOBAL_TYPE(Block));\n    });\n    context.reader.forAllInMap(node, &f);\n    context.reader.dispose();\n\n    // Add blocks to pack\n    for (auto& b : loadedBlocks) {\n        pack->append(b);\n    }\n\n    return true;\n}\n\n\nGameBlockPostProcess::GameBlockPostProcess(const vio::IOManager* iom, CaPhysicsTypeDict* caCache) :\n    m_iom(iom),\n    m_caCache(caCache) {\n    del = makeDelegate(this, &GameBlockPostProcess::invoke);\n}\n\nvoid GameBlockPostProcess::invoke(Sender s, ui16 id) {\n    Block& block = ((BlockPack*)s)->operator[](id);\n    block.active = true;\n\n    // Pack light color\n    block.lightColorPacked =\n        ((ui16)block.lightColor.r << LAMP_RED_SHIFT) |\n        ((ui16)block.lightColor.g << LAMP_GREEN_SHIFT) |\n        (ui16)block.lightColor.b;\n\n    // Ca Physics\n    if (block.caFilePath.length()) {\n        // Check if this physics type was already loaded\n        auto it = m_caCache->find(block.caFilePath);\n        if (it == m_caCache->end()) {\n            // TODO(Ben): Why new?\n            // TODO(Ben): This isn't getting stored...\n            CaPhysicsType* newType = new CaPhysicsType();\n            // Load in the data\n            if (newType->loadFromYml(block.caFilePath, m_iom)) {\n                block.caIndex = newType->getCaIndex();\n                block.caAlg = newType->getCaAlg();\n            } else {\n                delete newType;\n            }\n        } else {\n            block.caIndex = it->second->getCaIndex();\n            block.caAlg = it->second->getCaAlg();\n        }\n    }\n}\n\nbool BlockLoader::saveMapping(const vio::IOManager& iom, const cString filePath, BlockPack* pack) {    \n    vio::FileStream fs = iom.openFile(filePath, vio::FileOpenFlags::WRITE_ONLY_CREATE);\n    if (!fs.isOpened()) pError(\"Failed to open block mapping file for save\");\n\n    for (auto& b : pack->getBlockMap()) {\n        fs.write(\"%s: %d\\n\", b.first.c_str(), b.second);\n    }\n    return true;\n}\n\nbool BlockLoader::tryLoadMapping(const vio::IOManager& iom, const cString filePath, BlockPack* pack) {\n    vio::Path path;\n    if (!iom.resolvePath(filePath, path)) return false;\n\n    std::ifstream file(path.getCString());\n    if (file.fail()) return false;\n\n    // TODO(Ben): Handle comments\n    nString token;\n    BlockID id;\n    while (std::getline(file, token, ':')) {\n        // Read the id\n        file >> id;\n        pack->reserveID(token, id);\n        // Get the newline\n        char nl;\n        file.get(nl);\n    }\n    return true;\n}\n\nbool BlockLoader::saveBinary(const vio::IOManager& iom, const cString filePath, BlockPack* pack) {\n    vio::FileStream fs = iom.openFile(filePath, vio::FileOpenFlags::WRITE_ONLY_CREATE | vio::FileOpenFlags::BINARY);\n    if (!fs.isOpened()) return false;\n\n    ui32 size = pack->getBlockMap().size();\n    ui32 blockSize = sizeof(Block);\n    // Write sizes\n    fs.write(1, sizeof(ui32), &size);\n    fs.write(1, sizeof(ui32), &blockSize);\n\n    // TODO(Ben): This isn't complete.\n    const std::vector<Block>& blockList = pack->getBlockList();\n    for (auto& b : pack->getBlockMap()) {\n        const Block& block = blockList[b.second];\n        fs.write(\"%s\", block.name.c_str()); fs.write(1, 1, \"\\0\");\n        fs.write(1, sizeof(bool), &block.powderMove);\n        fs.write(1, sizeof(bool), &block.collide);\n        fs.write(1, sizeof(bool), &block.waterBreak);\n        fs.write(1, sizeof(bool), &block.blockLight);\n        fs.write(1, sizeof(bool), &block.useable);\n        fs.write(1, sizeof(bool), &block.allowLight);\n        fs.write(1, sizeof(bool), &block.isCrushable);\n        fs.write(1, sizeof(bool), &block.isSupportive);\n    }\n    return true;\n}\n\nvoid readStr(vio::FileStream& fs, char* buf) {\n    int i = 0;\n    do {\n        fs.read(1, sizeof(char), buf + i);\n    } while (buf[i++] != 0);\n}\n\nbool BlockLoader::loadBinary(const vio::IOManager& iom, const cString filePath, BlockPack* pack) {\n    vio::FileStream fs = iom.openFile(filePath, vio::FileOpenFlags::READ_ONLY_EXISTING | vio::FileOpenFlags::BINARY);\n    if (!fs.isOpened()) return false;\n\n    ui32 size;\n    ui32 blockSize;\n    // Read sizes\n    fs.read(1, sizeof(ui32), &size);\n    fs.read(1, sizeof(ui32), &blockSize);\n    // Make sure block size didn't change. DEBUG MODE CHANGES THE SIZE!!!\n    //if (blockSize != sizeof(Block)) return false;\n\n    char buf[512];\n\n    // TODO(Ben): This isn't complete.\n    for (ui32 i = 0; i < size; i++) {\n        Block b;\n        readStr(fs, buf);\n        b.name = buf;\n        fs.read(1, sizeof(bool), &b.powderMove);\n        fs.read(1, sizeof(bool), &b.collide);\n        fs.read(1, sizeof(bool), &b.waterBreak);\n        fs.read(1, sizeof(bool), &b.blockLight);\n        fs.read(1, sizeof(bool), &b.useable);\n        fs.read(1, sizeof(bool), &b.allowLight);\n        fs.read(1, sizeof(bool), &b.isCrushable);\n        fs.read(1, sizeof(bool), &b.isSupportive);\n        pack->append(b);\n    }\n    return true;\n}"
  },
  {
    "path": "SoA/BlockLoader.h",
    "content": "#pragma once\n\n#include <Vorb/Event.hpp>\n#include <Vorb/VorbPreDecl.inl>\n\n#include \"BlockData.h\"\n#include \"CAEngine.h\"\n\nDECL_VIO(class IOManager)\n\nclass BlockPack;\nclass TexturePackLoader;\n\nclass GameBlockPostProcess {\npublic:\n    GameBlockPostProcess(const vio::IOManager* iom, CaPhysicsTypeDict* caCache);\n\n    void invoke(Sender s, ui16 id);\n\n    Delegate<void, Sender, ui16> del;\nprivate:\n    const vio::IOManager* m_iom; ///< IO workspace\n    CaPhysicsTypeDict* m_caCache; ///< CA type cache\n};\n\nclass BlockLoader\n{\npublic:\n    /// Loads blocks from a .yml file\n    /// @return true on success, false on failure\n    static bool loadBlocks(const vio::IOManager& iom, BlockPack* pack);\n\n    /// Loads blocks from a .yml file\n    /// @param iom: IO workspace\n    /// @param filePath: The .yml file path\n    /// @param pack: Depository for all loaded blocks\n    /// @return true on success, false on failure\n    static bool load(const vio::IOManager& iom, const cString filePath, BlockPack* pack);\n\n    /// Saves blocks to a .yml file\n    /// @param filePath: The .yml file path\n    /// @param pack: Source of block data\n    /// @return true on success, false on failure\n    static bool saveBlocks(const nString& filePath, BlockPack* pack);\nprivate:\n    /// Sets up the water blocks. This is temporary\n    /// @param blocks: Output list for blocks\n    static void SetWaterBlocks(std::vector<Block>& blocks);\n\n    /// Saves the block mapping scheme\n    static bool saveMapping(const vio::IOManager& iom, const cString filePath, BlockPack* pack);\n\n    /// Tries to load an existing block mapping scheme\n    static bool tryLoadMapping(const vio::IOManager& iom, const cString filePath, BlockPack* pack);\n\n    /// Caches blocks in binary\n    static bool saveBinary(const vio::IOManager& iom, const cString filePath, BlockPack* pack);\n\n    /// Tries to load an existing block mapping scheme\n    static bool loadBinary(const vio::IOManager& iom, const cString filePath, BlockPack* pack);\n};\n\n"
  },
  {
    "path": "SoA/BlockPack.cpp",
    "content": "#include \"stdafx.h\"\n#include \"BlockPack.h\"\n\nBlockPack::BlockPack() :\n    onBlockAddition(this) {\n    \n    { // Create \"None\" block\n        Block b;\n        b.sID = \"none\";\n        b.name = \"None\";\n        b.allowLight = true;\n        b.collide = false;\n        b.floatingAction = 0;\n        b.meshType = MeshType::NONE;\n        b.occlude = BlockOcclusion::NONE;\n        b.isSupportive = false;\n        b.blockLight = false;\n        b.useable = true;\n        append(b);\n    }\n    { // Create \"Unknown\" block\n        Block b;\n        b.sID = \"Unknown\";\n        b.name = \"Unknown\";\n        append(b);\n    }\n}\n\nBlockID BlockPack::append(Block& block) {\n    const Block* curBlock;\n    BlockID rv;\n    if ((curBlock = hasBlock(block.sID))) {\n        rv = curBlock->ID;\n        block.ID = rv;\n        // Overwrite block\n        *const_cast<Block*>(curBlock) = block;\n    } else {\n        rv = m_blockList.size();\n        block.ID = rv;\n        // Add a new block\n        m_blockList.push_back(block);\n        // Set the correct index\n        m_blockMap[block.sID] = rv;\n    }\n    onBlockAddition(block.ID);\n    return rv;\n}\n\nvoid BlockPack::reserveID(const BlockIdentifier& sid, const BlockID& id) {\n    if (id >= m_blockList.size()) m_blockList.resize(id + 1);\n    m_blockMap[sid] = id;\n    m_blockList[id].ID = id;\n}\n"
  },
  {
    "path": "SoA/BlockPack.h",
    "content": "///\n/// BlockPack.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 23 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Container for block data\n///\n\n#pragma once\n\n#ifndef BlockPack_h__\n#define BlockPack_h__\n\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/Texture.h>\n\n#include \"BlockData.h\"\n\n/// A container for blocks\nclass BlockPack {\npublic:\n    /// Constructor which adds default none and unknown blocks\n    BlockPack();\n\n    /// Add a block to the pack, and overwrite a block of the same BlockIdentifier\n    /// Will invalidate existing Block* pointers. Store BlockIDs instead.\n    BlockID append(Block& block);\n\n    void reserveID(const BlockIdentifier& sid, const BlockID& id);\n\n    /// Note that the returned pointer becomes invalidated after an append call\n    /// @return nullptr if block doesn't exist\n    const Block* hasBlock(const BlockID& id) const {\n        if (id >= m_blockList.size()) {\n            return nullptr;\n        } else {\n            return &m_blockList[id];\n        }\n    }\n    const Block* hasBlock(const BlockIdentifier& sid) const {\n        auto v = m_blockMap.find(sid);\n        if (v == m_blockMap.end()) {\n            return nullptr;\n        } else {\n            return &m_blockList[v->second];\n        }\n    }\n\n    /// @return Number of blocks in this pack\n    size_t size() const {\n        return m_blockList.size();\n    }\n\n    /************************************************************************/\n    /* Block accessors                                                      */\n    /************************************************************************/\n    Block& operator[](const size_t& index) {\n        return m_blockList[index];\n    }\n    const Block& operator[](const size_t& index) const {\n        return m_blockList[index];\n    }\n    Block& operator[](const BlockIdentifier& sid) {\n        return m_blockList[m_blockMap.at(sid)];\n    }\n    const Block& operator[](const BlockIdentifier& sid) const {\n        return m_blockList[m_blockMap.at(sid)];\n    }\n    const ui16& getBlockIndex(const BlockIdentifier& sid) const {\n        return m_blockMap.at(sid);\n    }\n\n    const std::unordered_map<BlockIdentifier, ui16>& getBlockMap() const { return m_blockMap; }\n    const std::vector<Block>& getBlockList() const { return m_blockList; }\n\n    Event<ui16> onBlockAddition; ///< Signaled when a block is loaded\nprivate:\n    std::unordered_map<BlockIdentifier, ui16> m_blockMap; ///< Blocks indices organized by identifiers\n    std::vector<Block> m_blockList; ///< Block data list\n};\n\n#endif // BlockPack_h__\n"
  },
  {
    "path": "SoA/BlockTexture.cpp",
    "content": "#include \"stdafx.h\"\n#include \"BlockTexture.h\"\n\n#include \"BlockTexturePack.h\"\n\nKEG_ENUM_DEF(ConnectedTextureReducedMethod, ConnectedTextureReducedMethod, e) {\n    e.addValue(\"none\", ConnectedTextureReducedMethod::NONE);\n    e.addValue(\"top\", ConnectedTextureReducedMethod::TOP);\n    e.addValue(\"bottom\", ConnectedTextureReducedMethod::BOTTOM);\n}\nKEG_ENUM_DEF(BlendType, BlendType, e) {\n    e.addValue(\"add\", BlendType::ADD);\n    e.addValue(\"multiply\", BlendType::MULTIPLY);\n    e.addValue(\"replace\", BlendType::ALPHA);\n    e.addValue(\"subtract\", BlendType::SUBTRACT);\n}\n\nKEG_ENUM_DEF(ConnectedTextureMethods, ConnectedTextureMethods, e) {\n    e.addValue(\"none\", ConnectedTextureMethods::NONE);\n    e.addValue(\"connect\", ConnectedTextureMethods::CONNECTED);\n    e.addValue(\"random\", ConnectedTextureMethods::RANDOM);\n    e.addValue(\"repeat\", ConnectedTextureMethods::REPEAT);\n    e.addValue(\"grass\", ConnectedTextureMethods::GRASS);\n    e.addValue(\"horizontal\", ConnectedTextureMethods::HORIZONTAL);\n    e.addValue(\"vertical\", ConnectedTextureMethods::VERTICAL);\n    e.addValue(\"flora\", ConnectedTextureMethods::FLORA);\n}\nKEG_ENUM_DEF(ConnectedTextureSymmetry, ConnectedTextureSymmetry, e) {\n    e.addValue(\"none\", ConnectedTextureSymmetry::NONE);\n    e.addValue(\"opposite\", ConnectedTextureSymmetry::OPPOSITE);\n    e.addValue(\"all\", ConnectedTextureSymmetry::ALL);\n}\n\nKEG_TYPE_DEF_SAME_NAME(BlockTexture, kt) {\n    kt.addValue(\"base\", keg::Value::custom(offsetOf(BlockTexture, layers.base), \"BlockTextureLayer\"));\n    kt.addValue(\"overlay\", keg::Value::custom(offsetOf(BlockTexture, layers.overlay), \"BlockTextureLayer\"));\n    kt.addValue(\"blendMode\", keg::Value::custom(offsetOf(BlockTexture, blendMode), \"BlendType\", true));\n}\n\n/// \"less than\" operator for inserting into sets in TexturePackLoader\nbool BlockTextureLayer::operator<(const BlockTextureLayer& b) const {\n\n    // Helper macro for checking if !=\n#define LCHECK(a) if (a < b.a) { return true; } else if (a > b.a) { return false; }\n    LCHECK(path);\n    LCHECK(method);\n    LCHECK(size.x);\n    LCHECK(size.y);\n    LCHECK(symmetry);\n    LCHECK(color.r);\n    LCHECK(color.g);\n    LCHECK(color.b);\n    LCHECK(reducedMethod);\n    LCHECK(weights.size());\n    LCHECK(totalWeight);\n    LCHECK(numTiles);\n    LCHECK(innerSeams);\n    LCHECK(transparency);\n    return false;\n}\n\nvoid BlockTextureLayer::getFinalColor(OUT color3& resColor, ui8 temperature, ui8 rainfall, ui32 altColor VORB_UNUSED) const {\n    // TODO(Ben): Alternate colors\n    if (colorMap) {\n        // TODO(Ben): Store as floats to prevent cast overhead?\n        const color3& mapColor = colorMap->pixels[rainfall][temperature];\n        //Average the map color with the base color\n        resColor.r = (ui8)(((f32)color.r * (f32)mapColor.r) / 255.0f);\n        resColor.g = (ui8)(((f32)color.g * (f32)mapColor.g) / 255.0f);\n        resColor.b = (ui8)(((f32)color.b * (f32)mapColor.b) / 255.0f);\n    } /*else if (altColor > altColors.size()) { //alt colors, for leaves and such\n        baseColor = altColors[flags - 1];\n    } */else {\n        resColor = color;\n    }\n}"
  },
  {
    "path": "SoA/BlockTexture.h",
    "content": "///\n/// BlockTexture.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 16 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Texture information for blocks\n///\n\n#pragma once\n\n#ifndef BlockTexture_h__\n#define BlockTexture_h__\n\n#include <Vorb/io/Keg.h>\n\n#include \"BlockTextureMethods.h\"\n\n#define BASE_TYPE_INDEX 0\n#define NORM_TYPE_INDEX 1\n#define DISP_TYPE_INDEX 2\n\nstruct BlockColorMap;\n\nenum class ConnectedTextureMethods {\n    NONE,\n    CONNECTED,\n    HORIZONTAL,\n    VERTICAL,\n    GRASS,\n    REPEAT,\n    RANDOM,\n    FLORA\n};\nKEG_ENUM_DECL(ConnectedTextureMethods);\n\nenum class ConnectedTextureSymmetry {\n    NONE,\n    OPPOSITE,\n    ALL\n};\nKEG_ENUM_DECL(ConnectedTextureSymmetry);\n\nenum class ConnectedTextureReducedMethod {\n    NONE,\n    TOP,\n    BOTTOM\n};\nKEG_ENUM_DECL(ConnectedTextureReducedMethod);\n\nenum class BlendType {\n    ALPHA,\n    ADD,\n    SUBTRACT,\n    MULTIPLY\n};\nKEG_ENUM_DECL(BlendType);\n\nclass BlockTextureLayer {\npublic:\n    BlockTextureLayer() : method(ConnectedTextureMethods::NONE), size(1), symmetry(ConnectedTextureSymmetry::NONE),\n    reducedMethod(ConnectedTextureReducedMethod::NONE), colorMap(nullptr), averageColor(255, 255, 255), color(255, 255, 255),\n    floraHeight(0), totalWeight(0), numTiles(1), indices{0, 0, 0},  innerSeams(false), transparency(false), path(\"\"), normalPath(\"\"),\n    dispPath(\"\"), colorMapPath(\"\"), blockTextureFunc(BlockTextureMethods::getDefaultTextureIndex)\n        {}\n\n    static ui32 getFloraRows(ui32 floraMaxHeight) {\n        return (floraMaxHeight * floraMaxHeight + floraMaxHeight) / 2;\n    }\n\n    // Sets the texture func based on the method\n    // needs to have the method\n    void initBlockTextureFunc() {\n        switch (method) {\n            case ConnectedTextureMethods::CONNECTED:\n                blockTextureFunc = BlockTextureMethods::getConnectedTextureIndex;\n                break;\n            case ConnectedTextureMethods::RANDOM:\n                blockTextureFunc = BlockTextureMethods::getRandomTextureIndex;\n                break;\n            case ConnectedTextureMethods::GRASS:\n                blockTextureFunc = BlockTextureMethods::getGrassTextureIndex;\n                break;\n            case ConnectedTextureMethods::HORIZONTAL:\n                blockTextureFunc = BlockTextureMethods::getHorizontalTextureIndex;\n                break;\n            case ConnectedTextureMethods::VERTICAL:\n                blockTextureFunc = BlockTextureMethods::getVerticalTextureIndex;\n                break;\n            case ConnectedTextureMethods::FLORA:\n                blockTextureFunc = BlockTextureMethods::getFloraTextureIndex;\n                break;\n            default:\n                break;\n        }\n    }\n\n    // TODO(Ben): should it be ref color?\n    inline void getBlockTextureMethodData(BlockTextureMethodParams& params, OUT color3& color, OUT BlockTextureMethodData& data) const {\n        data.index = this->index.layer;\n        getTextureMethodData(params, BASE_TYPE_INDEX, color, data);\n    }\n    inline void getNormalTextureMethodData(BlockTextureMethodParams& params, OUT color3& color, OUT BlockTextureMethodData& data) const {\n        data.index = this->index.normal;\n        return getTextureMethodData(params, NORM_TYPE_INDEX, color, data);\n    }\n    inline void getDispTextureMethodData(BlockTextureMethodParams& params, OUT color3& color, OUT  BlockTextureMethodData& data) const {\n        data.index = this->index.disp;\n        return getTextureMethodData(params, DISP_TYPE_INDEX, color, data);\n    }\n    inline void getTextureMethodData(BlockTextureMethodParams& params, ui32 typeIndex, OUT color3& color, BlockTextureMethodData& data) const {\n        params.set(this, typeIndex, color);\n        blockTextureFunc(params, data);\n    }\n\n    void getFinalColor(OUT color3& color, ui8 temperature, ui8 rainfall, ui32 altColor) const;\n\n    ConnectedTextureMethods method;\n    ui8v2 size;\n    ConnectedTextureSymmetry symmetry;\n    ConnectedTextureReducedMethod reducedMethod;\n    BlockColorMap* colorMap;\n    color3 averageColor; // Average texture color combined with color (for terrain)\n    color3 color;\n    ui32 floraHeight;\n    Array<i32> weights;\n    ui32 totalWeight;\n    ui32 numTiles;\n    union {\n        struct {\n            BlockTextureIndex layer;\n            BlockTextureIndex normal;\n            BlockTextureIndex disp;\n        } index;\n        BlockTextureIndex indices[3];\n    };\n    bool innerSeams;\n    bool transparency;\n    nString path;\n    nString normalPath;\n    nString dispPath;\n    nString colorMapPath;\n    BlockTextureFunc blockTextureFunc;\n\n    /// \"less than\" operator for inserting into sets in TexturePackLoader\n    // TODO(Ben): Are these operators needed?\n    bool operator<(const BlockTextureLayer& b) const;\n    bool operator==(const BlockTextureLayer& b) const {\n        return method == b.method && size == b.size && symmetry == b.symmetry &&\n            reducedMethod == b.reducedMethod && colorMap == b.colorMap &&\n            color == b.color && \n            averageColor == b.averageColor && floraHeight == b.floraHeight &&\n            totalWeight == b.totalWeight && numTiles == b.numTiles && index.layer == b.index.layer &&\n            innerSeams == b.innerSeams && transparency == b.transparency && path == b.path;\n    }\n};\n\nstruct BlockTexture {\n    BlockTexture(): layers(), blendMode(BlendType::ALPHA)\n    {\n    }\n    //provide deconstructor because of union\n    ~BlockTexture()\n    {\n        layers.base.BlockTextureLayer::~BlockTextureLayer();\n        layers.overlay.BlockTextureLayer::~BlockTextureLayer();\n    }\n    \n    struct {\n        BlockTextureLayer base;\n        BlockTextureLayer overlay;\n    } layers;\n    BlendType blendMode;\n};\nKEG_TYPE_DECL(BlockTexture);\n\n#endif // BlockTexture_h__\n"
  },
  {
    "path": "SoA/BlockTextureAtlas.h",
    "content": "#pragma once\n\n// Number Of Tiles Per Side Of The Block Texture Atlas\nconst i32 BLOCK_TEXTURE_ATLAS_TILES_PER_SIDE = 16;\nconst i32 BLOCK_TEXTURE_ATLAS_TILES_PER_PAGE = BLOCK_TEXTURE_ATLAS_TILES_PER_SIDE * BLOCK_TEXTURE_ATLAS_TILES_PER_SIDE;\n\nclass BlockTextureIndex {\npublic:\n    BlockTextureIndex(ui16 blockID, i32 tileWidth, i32 tileHeight);\n    BlockTextureIndex() : BlockTextureIndex(0, 0, 0) {}\n\n    void setIndex(const i32& x, const i32& y) {\n        atlasUVRect[0] = (ui8)((x << 4) | y);\n    }\n    void setPage(const i32& page) {\n        atlasUVRect[1] = (ui8)page;\n    }\n    void setSize(const i32& x, const i32& y) {\n        atlasUVRect[2] = (ui8)((x << 4) | y);\n    }\n\n    // The Location And Size In The Atlas\n    ui8 atlasUVRect[3];\n\n    // Texturing Method\n    ui8 textureMethod;\n};\n\nclass BlockAtlasPage;\n\nclass BlockTextureAtlas {\npublic:\n    BlockTextureAtlas(i32 tileResolution);\n\n    void addTextures(std::vector<BlockTextureIndex>& textures);\nprivate:\n    i32v3 _atlasDimensions;\n    i32 _resolution;\n\n    std::vector<BlockAtlasPage*> _atlasPages;\n    std::vector<BlockTextureIndex*> _sortedOrderTiles;\n};"
  },
  {
    "path": "SoA/BlockTextureLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"BlockTextureLoader.h\"\n#include \"ModPathResolver.h\"\n#include \"BlockTexturePack.h\"\n#include \"BlockData.h\"\n#include \"Errors.h\"\n\n#include <Vorb/graphics/ImageIO.h>\n\n// Used for error checking\n#define CONNECTED_WIDTH 12\n#define CONNECTED_HEIGHT 4\n#define GRASS_WIDTH 3\n#define GRASS_HEIGHT 3\n#define HORIZONTAL_WIDTH 4\n#define HORIZONTAL_HEIGHT 1\n\nvoid BlockTextureLoader::init(ModPathResolver* texturePathResolver, BlockTexturePack* texturePack) {\n    m_texturePathResolver = texturePathResolver;\n    m_texturePack = texturePack;\n}\n\nvoid BlockTextureLoader::loadTextureData() {\n    if (!loadLayerProperties()) pError(\"Failed to load LayerProperties.yml\");\n    if (!loadTextureProperties()) pError(\"Failed to load Textures.yml\");\n    if (!loadBlockTextureMapping()) pError(\"Failed to load BlockTextureMapping.yml\");\n}\n\nvoid BlockTextureLoader::loadBlockTextures(Block& block) {\n    // Check for block mapping\n    auto it = m_blockMappings.find(block.sID);\n    if (it == m_blockMappings.end()) {\n        printf(\"Warning: Could not load texture mapping for block %s\\n\", block.sID.c_str());\n        for (int i = 0; i < 6; i++) {\n            block.textures[i] = m_texturePack->getDefaultTexture();\n        }\n        return;\n    }\n\n    // Load the textures for each face\n    BlockTextureNames& names = it->second;\n    for (int i = 0; i < 6; i++) {\n        BlockTexture* texture = m_texturePack->findTexture(names.names[i]);\n        if (texture) {\n            loadLayer(texture->layers.base);\n            if (texture->layers.overlay.path.size()) {\n                loadLayer(texture->layers.overlay);\n            }\n            block.textures[i] = texture;\n        } else {\n            block.textures[i] = m_texturePack->getDefaultTexture();\n            return;\n        }\n    }\n   \n    // TODO(Ben): NOPE\n    /* BlockTexture particleTexture;\n     GameManager::texturePackLoader->getBlockTexture(particleTexName, particleTexture);\n     particleTex = particleTexture.base.index;*/\n\n    // Calculate flora height\n    // TODO(Ben): This is dubious\n    if (block.textures[0]->layers.base.method == ConnectedTextureMethods::FLORA) {\n        // Just a bit of algebra to solve for n with the equation y = (n^2 + n) / 2\n        // which becomes n = (sqrt(8 * y + 1) - 1) / 2\n        int y = block.textures[0]->layers.base.size.y;\n        block.floraHeight = (ui16)(sqrt(8 * y + 1) - 1) / 2;\n    }\n}\n\nbool BlockTextureLoader::loadLayerProperties() {\n    vio::Path path;\n    if (!m_texturePathResolver->resolvePath(\"LayerProperties.yml\", path)) return false;\n\n    // Read file\n    nString data;\n    m_iom.readFileToString(path, data);\n    if (data.empty()) return false;\n\n    // Convert to YAML\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        context.reader.dispose();\n        return false;\n    }\n\n    // Layer handle for lf\n    BlockTextureLayer* lp;\n    // Custom values for parsing\n    keg::Value colorVal = keg::Value::basic(0, keg::BasicType::UI8_V3);\n    keg::Value methodVal = keg::Value::custom(0, \"ConnectedTextureMethods\", true);\n \n    // Custom layer parse\n    auto lf = makeFunctor([&, this](Sender, const nString& key, keg::Node value) {\n        if (key == \"path\") {\n            lp->path = keg::convert<nString>(value);\n        } else if (key == \"normalMap\") {\n            lp->normalPath = keg::convert<nString>(value);\n        } else if (key == \"dispMap\") {\n            lp->dispPath = keg::convert<nString>(value);\n        } else if (key == \"color\") {\n            switch (keg::getType(value)) {\n                case keg::NodeType::VALUE:\n                    lp->colorMapPath = keg::convert<nString>(value);\n                    lp->colorMap = this->getTexturePack()->getColorMap(lp->colorMapPath);\n                    break;\n                case keg::NodeType::SEQUENCE:\n                    keg::evalData((ui8*)&lp->color, &colorVal, value, context);\n                    break;\n                default:\n                    break;\n            }\n        } else if (key == \"altColors\") {\n            // TODO(Ben): Implement\n        } else if (key == \"method\") {\n            keg::evalData((ui8*)&lp->method, &methodVal, value, context);\n        } else if (key == \"coupling\") {\n            // TODO(Ben): Implement\n        }\n    });\n    // Load all layers\n    auto f = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        BlockTextureLayer layer;\n        lp = &layer;\n\n        // Manual parse\n        context.reader.forAllInMap(value, &lf);\n\n        // Cache the layer\n        m_layers[key] = layer;\n    });\n    context.reader.forAllInMap(node, &f);\n    context.reader.dispose();\n\n    return true;\n}\n\n// For parsing a block texture\n#define TEXTURE_PARSE_CODE \\\nif (key == \"base\") { \\\n    if (keg::getType(value) == keg::NodeType::MAP) { \\\n    } else { \\\n        nString base = keg::convert<nString>(value); \\\n       auto& it = m_layers.find(base); \\\n       if (it != m_layers.end()) { \\\n            texture->base = it->second; \\\n       } \\\n    } \\\n} else if (key == \"overlay\") { \\\n    if (keg::getType(value) == keg::NodeType::MAP) { \\\n    } else { \\\n      nString overlay = keg::convert<nString>(value); \\\n      auto& it = m_layers.find(overlay); \\\n        if (it != m_layers.end()) { \\\n            texture->overlay = it->second; \\\n        } \\\n    } \\\n} else if (key == \"blendMode\") { \\\n    nString v = keg::convert<nString>(value); \\\n    if (v == \"add\") { \\\n        texture->blendMode = BlendType::ADD; \\\n    } else if (v == \"multiply\") { \\\n    texture->blendMode = BlendType::MULTIPLY; \\\n    } else if (v == \"subtract\") { \\\n    texture->blendMode = BlendType::SUBTRACT; \\\n    } \\\n} \\\n\nbool BlockTextureLoader::loadTextureProperties() {\n    vio::Path path;\n    if (!m_texturePathResolver->resolvePath(\"Textures.yml\", path)) return false;\n\n    // Read file\n    nString data;\n    m_iom.readFileToString(path, data);\n    if (data.empty()) return false;\n\n    // Convert to YAML\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        context.reader.dispose();\n        return false;\n    }\n\n    BlockTexture* texture;\n    auto valf = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n//        TEXTURE_PARSE_CODE;\n        if(key==\"base\")\n        {\n            if(keg::getType(value)==keg::NodeType::MAP)\n            {\n            }\n            else\n            {\n                nString base=keg::convert<nString>(value);\n                auto it=m_layers.find(base);\n                if(it!=m_layers.end())\n                {\n                    texture->layers.base = it->second;\n                }\n            }\n        }\n        else if(key==\"overlay\")\n        {\n            if(keg::getType(value)==keg::NodeType::MAP)\n            {\n            }\n            else\n            {\n                nString overlay=keg::convert<nString>(value);\n                auto it=m_layers.find(overlay);\n                if(it!=m_layers.end())\n                {\n\n                    texture->layers.overlay = it->second;\n                }\n            }\n        }\n        else if(key==\"blendMode\")\n        {\n            nString v=keg::convert<nString>(value);\n            if(v==\"add\")\n            {\n                texture->blendMode=BlendType::ADD;\n            }\n            else if(v==\"multiply\")\n            {\n                texture->blendMode=BlendType::MULTIPLY;\n            }\n            else if(v==\"subtract\")\n            {\n                texture->blendMode=BlendType::SUBTRACT;\n            }\n        }\n    });\n\n    // Load all layers\n    auto f = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        texture = m_texturePack->getNextFreeTexture(key);\n        context.reader.forAllInMap(value, &valf);\n    });\n    context.reader.forAllInMap(node, &f);\n    context.reader.dispose();\n\n    return true;\n}\n\nbool BlockTextureLoader::loadBlockTextureMapping() {\n\n    vio::Path path;\n    if (!m_texturePathResolver->resolvePath(\"BlockTextureMapping.yml\", path)) return false;\n\n    // Read file\n    nString data;\n    const nString* blockName;\n    BlockTexture* texture;\n    m_iom.readFileToString(path, data);\n    if (data.empty()) return false;\n\n    // Convert to YAML\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        context.reader.dispose();\n        return false;\n    }\n\n    // For parsing textures\n    auto texParseFunctor = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        if (key == \"base\") {\n            if (keg::getType(value) == keg::NodeType::MAP) {\n\n            } else {\n\n                nString base = keg::convert<nString>(value);\n                auto it = m_layers.find(base);\n                if (it != m_layers.end()) {\n                    texture->layers.base = it->second;\n                }\n            }\n        } else if (key == \"overlay\") {\n            if (keg::getType(value) == keg::NodeType::MAP) {\n\n            } else {\n                nString overlay = keg::convert<nString>(value);\n                auto it = m_layers.find(overlay);\n                if (it != m_layers.end()) {\n\n                    texture->layers.overlay = it->second;\n                }\n            }\n        } else if (key == \"blendMode\") {\n            nString v = keg::convert<nString>(value);\n            if (v == \"add\") {\n                texture->blendMode = BlendType::ADD;\n            } else if (v == \"multiply\") {\n                texture->blendMode = BlendType::MULTIPLY;\n            } else if (v == \"subtract\") {\n                texture->blendMode = BlendType::SUBTRACT;\n            }\n        }\n    });\n\n    nString *texNames;\n\n    auto valParseFunctor = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        nString name;\n        // Conditional parsing, map vs value\n        if (keg::getType(value) == keg::NodeType::MAP) {\n            name = *blockName + std::to_string(m_generatedTextureCounter++);\n            texture = m_texturePack->getNextFreeTexture(name);\n            context.reader.forAllInMap(value, &texParseFunctor);\n        } else {\n            name = keg::convert<nString>(value);\n        }\n\n        if (key == \"texture\") {\n            texNames[0] = name;\n        } else if (key == \"textureOpX\") {\n            texNames[1] = name;\n        } else if (key == \"textureOpY\") {\n            texNames[2] = name;\n        } else if (key == \"textureOpZ\") {\n            texNames[3] = name;\n        } else if (key == \"textureTop\") {\n            texNames[4] = name;\n        } else if (key == \"textureBottom\") {\n            texNames[5] = name;\n        } else if (key == \"textureFront\") {\n            texNames[6] = name;\n        } else if (key == \"textureBack\") {\n            texNames[7] = name;\n        } else if (key == \"textureLeft\") {\n            texNames[8] = name;\n        } else if (key == \"textureRight\") {\n            texNames[9] = name;\n        }\n    });\n\n    // Load all layers\n    auto f = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        BlockTextureNames tNames = {};\n        // So we can prioritize.\n        nString textureNames[10];\n        texNames = textureNames;\n\n        blockName = &key;\n        context.reader.forAllInMap(value, &valParseFunctor);\n\n        // Set textures based on names\n        if (texNames[0].size()) {\n            for (int i = 0; i < 6; i++) {\n                tNames.names[i] = texNames[0];\n            }\n        }\n        if (texNames[1].size()) {\n            tNames.names[(int)vvox::Cardinal::X_NEG] = texNames[1];\n            tNames.names[(int)vvox::Cardinal::X_POS] = texNames[1];\n        }\n        if (texNames[2].size()) {\n            tNames.names[(int)vvox::Cardinal::Y_NEG] = texNames[2];\n            tNames.names[(int)vvox::Cardinal::Y_POS] = texNames[2];\n        }\n        if (texNames[3].size()) {\n            tNames.names[(int)vvox::Cardinal::Z_NEG] = texNames[3];\n            tNames.names[(int)vvox::Cardinal::Z_POS] = texNames[3];\n        }\n        if (texNames[4].size()) {\n            tNames.names[(int)vvox::Cardinal::Y_POS] = texNames[4];\n        }\n        if (texNames[5].size()) {\n            tNames.names[(int)vvox::Cardinal::Y_NEG] = texNames[5];\n        }\n        if (texNames[6].size()) {\n            tNames.names[(int)vvox::Cardinal::Z_POS] = texNames[6];\n        }\n        if (texNames[7].size()) {\n            tNames.names[(int)vvox::Cardinal::Z_NEG] = texNames[7];\n        }\n        if (texNames[8].size()) {\n            tNames.names[(int)vvox::Cardinal::X_NEG] = texNames[8];\n        }\n        if (texNames[9].size()) {\n            tNames.names[(int)vvox::Cardinal::X_POS] = texNames[9];\n        }\n\n        // Set mappings\n        m_blockMappings[key] = tNames;\n    });\n    context.reader.forAllInMap(node, &f);\n    context.reader.dispose();\n\n    return true;\n}\n\nbool BlockTextureLoader::loadLayer(BlockTextureLayer& layer) {\n    AtlasTextureDescription desc = m_texturePack->findLayer(layer.path);\n    // Check if its already been loaded\n    if (desc.size.x != 0) {\n        // Already loaded so just use the desc\n        // TODO(Ben): Worry about different methods using same file?\n        layer.size = desc.size;\n        layer.index.layer = desc.index;\n    } else {\n        vio::Path path;\n        if (!m_texturePathResolver->resolvePath(layer.path, path)) return false;\n        { // Get pixels for the base texture\n            vg::ScopedBitmapResource rs(vg::ImageIO().load(path, vg::ImageIOFormat::RGBA_UI8));\n            // Do post processing on the layer\n            if (!postProcessLayer(rs, layer)) return false;\n        \n            layer.index.layer = m_texturePack->addLayer(layer, layer.path, (color4*)rs.bytesUI8v4);\n        }\n        // Normal map\n        if (layer.normalPath.size() && m_texturePathResolver->resolvePath(layer.normalPath, path)) {\n            vg::ScopedBitmapResource rs(vg::ImageIO().load(path, vg::ImageIOFormat::RGBA_UI8));\n            // Do post processing on the layer\n            if (rs.data) {\n                layer.index.normal = m_texturePack->addLayer(layer, layer.normalPath, (color4*)rs.bytesUI8v4);\n            }\n        }\n        // disp map\n        if (layer.dispPath.size() && m_texturePathResolver->resolvePath(layer.dispPath, path)) {\n            vg::ScopedBitmapResource rs(vg::ImageIO().load(path, vg::ImageIOFormat::RGBA_UI8));\n            // Do post processing on the layer\n            if (rs.data) {\n                layer.index.disp = m_texturePack->addLayer(layer, layer.dispPath, (color4*)rs.bytesUI8v4);\n            }\n        }\n    }\n    return true;\n}\n\nbool BlockTextureLoader::postProcessLayer(vg::ScopedBitmapResource& bitmap, BlockTextureLayer& layer) {\n\n    // ui32 floraRows;\n    const ui32& resolution = m_texturePack->getResolution();\n\n    // TODO(Ben): Floraheight\n\n    // Helper for checking dimensions\n#define DIM_CHECK(w, cw, h, ch, method) \\\n    if (bitmap.width != resolution * cw) { \\\n        pError(\"Texture \" + layer.path + \" is \" #method \" but width is not \" + std::to_string(cw)); \\\n        return false; \\\n            } \\\n    if (bitmap.height != resolution * ch) {  \\\n        pError(\"Texture \" + layer.path + \" is \" #method \" but height is not \" + std::to_string(ch)); \\\n        return false; \\\n            }\n\n    // Pixels must exist\n    if (!bitmap.data) return false;\n\n    // Check that the texture is sized in units of resolution\n    if (bitmap.width % resolution) {\n        pError(\"Texture \" + layer.path + \" width must be a multiple of \" + std::to_string(resolution));\n        return false;\n    }\n    if (bitmap.height % resolution) {\n        pError(\"Texture \" + layer.path + \" height must be a multiple of \" + std::to_string(resolution));\n        return false;\n    }\n\n    // Check for errors and postprocessing based on method\n    switch (layer.method) {\n        // Need to set up numTiles and totalWeight for RANDOM method\n        case ConnectedTextureMethods::CONNECTED:\n            layer.size = ui8v2(1);\n            DIM_CHECK(width, CONNECTED_WIDTH, bitmap.height, CONNECTED_HEIGHT, CONNECTED);\n            break;\n        case ConnectedTextureMethods::RANDOM:\n            layer.numTiles = bitmap.width / bitmap.height;\n            layer.size = ui32v2(1);\n            if (layer.weights.size() == 0) {\n                layer.totalWeight = layer.numTiles;\n            } else { // Need to check if there is the right number of weights\n                if (layer.weights.size() * resolution != bitmap.width) {\n                    pError(\"Texture \" + layer.path + \" weights length must match number of columns or be empty. weights.length() = \" +\n                           std::to_string(layer.weights.size()) + \" but there are \" + std::to_string(bitmap.width / resolution) + \" columns.\");\n                    return false;\n                }\n            }\n            break;\n        case ConnectedTextureMethods::GRASS:\n            layer.size = ui8v2(1);\n            DIM_CHECK(width, GRASS_WIDTH, bitmap.height, GRASS_HEIGHT, GRASS);\n            break;\n        case ConnectedTextureMethods::HORIZONTAL:\n            layer.size.x = (ui8)(bitmap.width / resolution);\n            layer.size.y = (ui8)(bitmap.height / resolution);\n            DIM_CHECK(width, HORIZONTAL_WIDTH, bitmap.height, HORIZONTAL_HEIGHT, HORIZONTAL);\n            break;\n        case ConnectedTextureMethods::VERTICAL:\n            layer.size.x = (ui8)(bitmap.width / resolution);\n            layer.size.y = (ui8)(bitmap.height / resolution);\n            DIM_CHECK(width, HORIZONTAL_HEIGHT, bitmap.height, HORIZONTAL_WIDTH, VERTICAL);\n            break;\n        case ConnectedTextureMethods::REPEAT:\n            layer.size.x = (ui8)(bitmap.width / resolution);\n            layer.size.y = (ui8)(bitmap.height / resolution);\n            DIM_CHECK(width, layer.size.x, bitmap.height, layer.size.y, REPEAT);\n            break;\n        //case ConnectedTextureMethods::FLORA:\n        //    floraRows = BlockTextureLayer::getFloraRows(layer.floraHeight);\n        //    if (bitmap.height != resolution * floraRows) {\n        //        pError(\"Texture \" + layer.path + \" texture height must be equal to (maxFloraHeight^2 + maxFloraHeight) / 2 * resolution = \" +\n        //               std::to_string(bitmap.height) + \" but it is \" + std::to_string(resolution * floraRows));\n        //        return false;\n        //    }\n        //    // If no weights, they are all equal\n        //    if (layer.weights.size() == 0) {\n        //        layer.totalWeight = bitmap.width / resolution;\n        //    } else { // Need to check if there is the right number of weights\n        //        if (layer.weights.size() * resolution != bitmap.width) {\n        //            pError(\"Texture \" + layer.path + \" weights length must match number of columns or be empty. weights.length() = \" +\n        //                   std::to_string(layer.weights.size()) + \" but there are \" + std::to_string(bitmap.width / resolution) + \" columns.\");\n        //            return false;\n        //        }\n        //    }\n        //    // Tile dimensions and count\n        //    layer.size.x = bitmap.width / resolution;\n        //    layer.size.y = floraRows;\n        //    layer.numTiles = layer.size.x * layer.size.y;\n        //    break;\n        case ConnectedTextureMethods::NONE:\n            DIM_CHECK(bitmap.width, 1, bitmap.height, 1, NONE);\n            break;\n        default:\n            break;\n    }\n\n    layer.initBlockTextureFunc();\n    return true;\n}"
  },
  {
    "path": "SoA/BlockTextureLoader.h",
    "content": "///\n/// BlockTextureLoader.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 16 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Loads block textures\n///\n\n#pragma once\n\n#ifndef BlockTextureLoader_h__\n#define BlockTextureLoader_h__\n\n#include <Vorb/io/IOManager.h>\n#include <Vorb/VorbPreDecl.inl>\n\n#include \"BlockData.h\"\n\nDECL_VG(class ScopedBitmapResource)\n\nclass Block;\nclass BlockTexturePack;\nclass ModPathResolver;\nclass BlockTextureLayer;\nstruct BlockTexture;\n\nstruct BlockTextureNames {\n    nString names[6];\n};\n\nclass BlockTextureLoader {\npublic:\n    void init(ModPathResolver* texturePathResolver, BlockTexturePack* texturePack);\n\n    void loadTextureData();\n\n    void loadBlockTextures(Block& block);\n\n    void dispose();\n\n    BlockTexturePack* getTexturePack() const { return m_texturePack; }\nprivate:\n    bool loadLayerProperties();\n    bool loadTextureProperties();\n    bool loadBlockTextureMapping();\n    bool loadLayer(BlockTextureLayer& layer);\n    bool postProcessLayer(vg::ScopedBitmapResource& bitmap, BlockTextureLayer& layer);\n\n    std::map<nString, BlockTextureLayer> m_layers;\n    std::map<BlockIdentifier, BlockTextureNames> m_blockMappings;\n\n    ModPathResolver* m_texturePathResolver = nullptr;\n    BlockTexturePack* m_texturePack = nullptr;\n    vio::IOManager m_iom;\n    int m_generatedTextureCounter = 0;\n};\n\n#endif // BlockTextureLoader_h__\n"
  },
  {
    "path": "SoA/BlockTextureMethods.cpp",
    "content": "#include \"stdafx.h\"\n#include \"BlockTextureMethods.h\"\n\n#include <Vorb/graphics/ConnectedTextures.h>\n#include <Vorb/utils.h>\n#include <Vorb/Random.h>\n\n#include \"BlockPack.h\"\n#include \"Chunk.h\"\n#include \"ChunkMesh.h\"\n#include \"ChunkMesher.h\"\n#include \"VoxelBits.h\"\n#include \"soaUtils.h\"\n\n#define GETBLOCK(a) (((*blocks)[((a) & 0x0FFF)]))\n// We are assuming layerIndex can be trusted to be 0 or 1 here, add asserts?\n#define TEXTURE_INDEX (params.layerIndex == 0 ? \\\n    block->textures[params.faceIndex]->layers.base.indices[params.typeIndex] : \\\n    block->textures[params.faceIndex]->layers.overlay.indices[params.typeIndex])\n\ninline ui32 getPositionSeed(const i32v3& pos) {\n    i32 val = ((pos.x & 0x7ff) | ((pos.y & 0x3ff) << 11) | ((pos.z & 0x7ff) << 21));\n    // Treat i32 bits as ui32 so we don't just truncate with a cast\n    return *(ui32*)&val;\n}\n\nvoid BlockTextureMethods::getDefaultTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result) {\n    result.size = params.blockTexInfo->size;\n} \n\n//Gets a random offset for use by random textures\nvoid BlockTextureMethods::getRandomTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result) {\n    //TODO: MurmurHash3\n    const ChunkMesher* cm = params.chunkMesher;\n    const BlockTextureLayer* blockTexInfo = params.blockTexInfo;\n    i32v3 pos(cm->chunkVoxelPos.pos.x + cm->bx, cm->chunkVoxelPos.pos.y + cm->by, cm->chunkVoxelPos.pos.z + cm->bz);\n\n    // TODO(Ben): Faster RNG?\n    f32 r = params.blockTexInfo->totalWeight * ((f32)rand() / RAND_MAX);\n    f32 totalWeight = 0;\n\n    result.size = params.blockTexInfo->size;\n    // TODO(Ben): Binary search?\n    if (blockTexInfo->weights.size()) {\n        for (ui32 i = 0; i < blockTexInfo->numTiles; i++) {\n            totalWeight += blockTexInfo->weights[i];\n            if (r <= totalWeight) {\n                result.index += i;\n                return;\n            }\n        }\n    } else {\n        for (ui32 i = 0; i < blockTexInfo->numTiles; i++) {\n            totalWeight += 1.0f;\n            if (r <= totalWeight) {\n                result.index += i;\n                return;\n            }\n        }\n    }\n}\n\nvoid BlockTextureMethods::getFloraTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result) {\n    //TODO: MurmurHash3\n    const ChunkMesher* cm = params.chunkMesher;\n    // i32 seed = 0; // getPositionSeed(cm->x + cm->position.x, cm->y + cm->position.y, cm->z + cm->position.z);\n\n    f32 r = (f32)((/*PseudoRand(seed) +*/ 1.0) * 0.5 * params.blockTexInfo->totalWeight);\n    f32 totalWeight = 0;\n\n    const BlockTextureLayer* blockTexInfo = params.blockTexInfo;\n    const ui16* tertiaryData = cm->tertiaryData;\n\n    const int& blockIndex = cm->blockIndex;\n\n    int column=0;\n\n    // TODO(Ben): Binary search?\n    if (blockTexInfo->weights.size()) {\n        for (ui32 i = 0; i < blockTexInfo->size.x; i++) {\n            totalWeight += blockTexInfo->weights[i];\n            if (r <= totalWeight) {\n                column = i;\n                break;\n            }\n        }\n    } else {\n        for (ui32 i = 0; i < blockTexInfo->size.x; i++) {\n            totalWeight += 1.0f;\n            if (r <= totalWeight) {\n                column = i;\n                break;\n            }\n        }\n    }\n\n    result.index += column;\n\n    // Get the height of the current voxel\n    int height = MIN(VoxelBits::getFloraHeight(tertiaryData[blockIndex]), cm->block->floraHeight);\n    int yPos = height - VoxelBits::getFloraPosition(tertiaryData[blockIndex]);\n\n    // Move the result to the flora of the correct height\n    result.index += blockTexInfo->size.x * (height * height + height) / 2;\n    // Offset by the ypos\n    result.index += blockTexInfo->size.x * yPos;\n    result.size = params.blockTexInfo->size;\n}\n\n//Gets a connected texture offset by looking at the surrounding blocks\nvoid BlockTextureMethods::getConnectedTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result) {\n    const BlockPack* blocks = params.chunkMesher->blocks;\n    int connectedOffset = 0;\n    const int& blockIndex = params.chunkMesher->blockIndex;\n    const int& upDir = params.upDir;\n    const int& rightDir = params.rightDir;\n    const int& frontDir = params.frontDir;\n    const ui16* blockIDData = params.chunkMesher->blockData;\n    BlockTextureIndex tex = result.index;\n\n    // Top Left\n    const Block *block = &GETBLOCK(blockIDData[blockIndex + upDir - rightDir]);\n\n    if (TEXTURE_INDEX != tex) {\n        connectedOffset |= 0x80;\n    }\n\n    // Top\n    block = &GETBLOCK(blockIDData[blockIndex + upDir]);\n    if (TEXTURE_INDEX != tex) {\n        connectedOffset |= 0xE0;\n    }\n\n    // Top Right\n    block = &GETBLOCK(blockIDData[blockIndex + upDir + rightDir]);\n    if (TEXTURE_INDEX != tex) {\n        connectedOffset |= 0x20;\n    }\n\n    // Right\n    block = &GETBLOCK(blockIDData[blockIndex + rightDir]);\n    if (TEXTURE_INDEX != tex) {\n        connectedOffset |= 0x38;\n    }\n\n    // Bottom Right\n    block = &GETBLOCK(blockIDData[blockIndex - upDir + rightDir]);\n    if (TEXTURE_INDEX != tex) {\n        connectedOffset |= 0x8;\n    }\n\n    // Bottom\n    block = &GETBLOCK(blockIDData[blockIndex - upDir]);\n    if (TEXTURE_INDEX != tex) {\n        connectedOffset |= 0xE;\n    }\n\n    // Bottom Left\n    block = &GETBLOCK(blockIDData[blockIndex - upDir - rightDir]);\n    if (TEXTURE_INDEX != tex) {\n        connectedOffset |= 0x2;\n    }\n\n    // Left\n    block = &GETBLOCK(blockIDData[blockIndex - rightDir]);\n    if (TEXTURE_INDEX != tex) {\n        connectedOffset |= 0x83;\n    }\n\n    if (params.blockTexInfo->innerSeams) {\n        // Top Front Left\n        block = &GETBLOCK(blockIDData[blockIndex + upDir - rightDir + frontDir]);\n        if (block->occlude != BlockOcclusion::NONE) {\n            connectedOffset |= 0x80;\n        }\n\n        // Top Front Right\n        block = &GETBLOCK(blockIDData[blockIndex + upDir + rightDir + frontDir]);\n        if (block->occlude != BlockOcclusion::NONE) {\n            connectedOffset |= 0x20;\n        }\n\n        // Bottom front Right\n        block = &GETBLOCK(blockIDData[blockIndex - upDir + rightDir + frontDir]);\n        if (block->occlude != BlockOcclusion::NONE) {\n            connectedOffset |= 0x8;\n        }\n\n        //Bottom front\n        block = &GETBLOCK(blockIDData[blockIndex - upDir + frontDir]);\n        if (block->occlude != BlockOcclusion::NONE) {\n            connectedOffset |= 0xE;\n        }\n\n        // Bottom front Left\n        block = &GETBLOCK(blockIDData[blockIndex - upDir - rightDir + frontDir]);\n        if (block->occlude != BlockOcclusion::NONE) {\n            connectedOffset |= 0x2;\n        }\n\n        //Left front\n        block = &GETBLOCK(blockIDData[blockIndex - rightDir + frontDir]);\n        if (block->occlude != BlockOcclusion::NONE) {\n            connectedOffset |= 0x83;\n        }\n\n        //Top front\n        block = &GETBLOCK(blockIDData[blockIndex + upDir + frontDir]);\n        if (block->occlude != BlockOcclusion::NONE) {\n            connectedOffset |= 0xE0;\n        }\n\n        //Right front\n        block = &GETBLOCK(blockIDData[blockIndex + rightDir + frontDir]);\n        if (block->occlude != BlockOcclusion::NONE) {\n            connectedOffset |= 0x38;\n        }\n    }\n    result.size = params.blockTexInfo->size;\n    result.index += vg::ConnectedTextureHelper::getOffsetFull(connectedOffset);\n}\n\n//Gets a grass side texture offset by looking at the surrounding blocks\nvoid BlockTextureMethods::getGrassTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result) {\n    const BlockPack* blocks = params.chunkMesher->blocks;\n    int connectedOffset = 0;\n    const int& blockIndex = params.chunkMesher->blockIndex;\n    const int& upDir = params.upDir;\n    const int& rightDir = params.rightDir;\n    const int& frontDir = params.frontDir;\n    const ui16* blockIDData = params.chunkMesher->blockData;\n   \n    const ChunkMesher* cm = params.chunkMesher;\n\n    BlockTextureIndex tex = result.index;\n\n    // Bottom Front\n    int index = blockIndex - upDir + frontDir;\n    int id = blockIDData[index];\n    const Block* block = &GETBLOCK(id);\n\n    if (/*cm->levelOfDetail > 1 || */ TEXTURE_INDEX == tex) {\n        block = &GETBLOCK(blockIDData[blockIndex]);\n        result.index = block->textureTop->layers.base.index.layer;\n        block->textureTop->layers.base.blockTextureFunc(params, result);\n        block->textureTop->layers.base.getFinalColor(*params.color, cm->heightData->temperature, cm->heightData->humidity, 0);\n        result.size = block->textureTop->layers.base.size;\n        return;\n    }\n\n    // Left\n    block = &GETBLOCK(blockIDData[blockIndex - rightDir]);\n    if (TEXTURE_INDEX == tex || block->occlude == BlockOcclusion::NONE) {\n        connectedOffset |= 0x8;\n\n        // REDUNDANT\n        if (TEXTURE_INDEX == tex) {\n            // bottom front Left\n            block = &GETBLOCK(blockIDData[blockIndex - upDir - rightDir + frontDir]);\n            if (TEXTURE_INDEX == tex) {\n                connectedOffset |= 0xC;\n            }\n        }\n    }\n\n    // Front left\n    block = &GETBLOCK(blockIDData[blockIndex - rightDir + frontDir]);\n    if (TEXTURE_INDEX == tex) {\n        connectedOffset |= 0x8;\n    }\n\n    // Bottom left\n    block = &GETBLOCK(blockIDData[blockIndex - upDir - rightDir]);\n    if (TEXTURE_INDEX == tex) {\n        connectedOffset |= 0xC;\n    }\n\n    // bottom right\n    block = &GETBLOCK(blockIDData[blockIndex - upDir + rightDir]);\n    if (TEXTURE_INDEX == tex) {\n        connectedOffset |= 0x3;\n    }\n\n    // Right\n    block = &GETBLOCK(blockIDData[blockIndex + rightDir]);\n    if (TEXTURE_INDEX == tex || block->occlude == BlockOcclusion::NONE) {\n        connectedOffset |= 0x1;\n\n        if (TEXTURE_INDEX == tex) {\n            // bottom front Right\n            block = &GETBLOCK(blockIDData[blockIndex - upDir + rightDir + frontDir]);\n            if (TEXTURE_INDEX == tex) {\n                connectedOffset |= 0x3;\n            }\n        }\n    }\n\n    // Front right\n    block = &GETBLOCK(blockIDData[blockIndex + rightDir + frontDir]);\n    if (TEXTURE_INDEX == tex) {\n        connectedOffset |= 0x1;\n    }\n    result.size = params.blockTexInfo->size;\n    result.index += vg::ConnectedTextureHelper::getOffsetSmall(connectedOffset);\n}\n\nvoid BlockTextureMethods::getVerticalTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result) {\n    const BlockPack* blocks = params.chunkMesher->blocks;\n    static int verticalOffsets[4] = { 0, 1, 3, 2 };\n\n    int connectedOffset;\n    const int& blockIndex = params.chunkMesher->blockIndex;\n    const int& upDir = params.upDir;\n    const ui16* blockIDData = params.chunkMesher->blockData;\n    const ConnectedTextureReducedMethod& rm = params.blockTexInfo->reducedMethod;\n\n    BlockTextureIndex tex = result.index;\n\n    if (rm == ConnectedTextureReducedMethod::NONE) {\n        connectedOffset = 0;\n    } else if (rm == ConnectedTextureReducedMethod::TOP) {\n        connectedOffset = 1;\n    } else { //BOTTOM\n        connectedOffset = 2;\n    }\n\n    //top bit\n    const Block *block = &GETBLOCK(blockIDData[blockIndex + upDir]);\n\n    if (TEXTURE_INDEX == tex) {\n        connectedOffset |= 2;\n    }\n    //bottom bit\n    block = &GETBLOCK(blockIDData[blockIndex - upDir]);\n    if (TEXTURE_INDEX == tex) {\n        connectedOffset |= 1;\n    }\n    result.size = params.blockTexInfo->size;\n    result.index += verticalOffsets[connectedOffset];\n}\n\nvoid BlockTextureMethods::getHorizontalTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result) {\n    static int horizontalOffsets[4] = { 0, 1, 3, 2 };\n    const BlockPack* blocks = params.chunkMesher->blocks;\n\n    int connectedOffset = 0;\n    const int& blockIndex = params.chunkMesher->blockIndex;\n    const int& rightDir = params.rightDir;\n    const int& frontDir = params.frontDir;\n    const ui16* blockIDData = params.chunkMesher->blockData;\n    BlockTextureIndex tex = result.index;\n\n    //right bit\n    const Block *block = &GETBLOCK(blockIDData[blockIndex + rightDir]);\n\n    if (TEXTURE_INDEX == tex) {\n        connectedOffset |= 1;\n    }\n    //left bit\n    block = &GETBLOCK(blockIDData[blockIndex - rightDir]);\n    if (TEXTURE_INDEX == tex) {\n        connectedOffset |= 2;\n    }\n\n    if (params.blockTexInfo->innerSeams) {\n        //front right bit\n        block = &GETBLOCK(blockIDData[blockIndex + rightDir + frontDir]);\n        if (TEXTURE_INDEX == tex) {\n            connectedOffset &= 2;\n        }\n        //front left bit\n        block = &GETBLOCK(blockIDData[blockIndex - rightDir + frontDir]);\n        if (TEXTURE_INDEX == tex) {\n            connectedOffset &= 1;\n        }\n    }\n    result.size = params.blockTexInfo->size;\n    result.index += horizontalOffsets[connectedOffset];\n}\n"
  },
  {
    "path": "SoA/BlockTextureMethods.h",
    "content": "///\n/// BlockTextureMethods.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 7 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// This file provides the texturing methods functions for block textures,\n/// such as connected textures and random textures.\n///\n\n#pragma once\n\n#ifndef BlockTextureMethods_h__\n#define BlockTextureMethods_h__\n\n#include <functional>\n#include <Vorb/types.h>\n\nclass ChunkMesher;\nclass BlockTextureLayer;\nclass BlockPack;\n\ntypedef ui32 BlockTextureIndex;\n\nclass BlockTextureMethodParams {\npublic:\n\n    void init(ChunkMesher* cm, i32 RightDir, i32 UpDir, i32 FrontDir, ui32 face, ui32 layerIndex) {\n        chunkMesher = cm;\n        rightDir = RightDir;\n        upDir = UpDir;\n        frontDir = FrontDir;\n        faceIndex = face;\n        this->layerIndex = layerIndex;\n    }\n\n    void set(const BlockTextureLayer* blockTextureLayer, ui32 typeIndex, ColorRGB8& Color) {\n        blockTexInfo = blockTextureLayer;\n        this->typeIndex = typeIndex;\n        color = &Color;\n    }\n\n    const ChunkMesher* chunkMesher = nullptr;\n    const BlockTextureLayer* blockTexInfo = nullptr;\n    i32 rightDir;\n    i32 upDir;\n    i32 frontDir;\n    ui32 faceIndex;\n    ui32 layerIndex;\n    ui32 typeIndex;\n    ColorRGB8* color = nullptr;\n};\n\nstruct BlockTextureMethodData {\n    BlockTextureIndex index;\n    ui8v2 size;\n};\n\ntypedef std::function <void(BlockTextureMethodParams& params, BlockTextureMethodData& result)> BlockTextureFunc;\n\nnamespace BlockTextureMethods {\n    void getDefaultTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result);\n    void getRandomTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result);\n    void getFloraTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result);\n    void getConnectedTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result);\n    void getGrassTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result);\n    void getVerticalTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result);\n    void getHorizontalTextureIndex(BlockTextureMethodParams& params, BlockTextureMethodData& result);\n}\n\n#endif // BlockTextureMethods_h__\n"
  },
  {
    "path": "SoA/BlockTexturePack.cpp",
    "content": "#include \"stdafx.h\"\n#include \"BlockTexturePack.h\"\n\n#include \"BlockPack.h\" // TEMPORARY\n#include \"BlockTexture.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"SpaceSystemAssemblages.h\"\n\n#include <SDL2/SDL.h>\n\n#include \"Errors.h\"\n\n#define CONNECTED_TILES 47\n#define GRASS_TILES 9\n#define HORIZONTAL_TILES 4\n#define VERTICAL_TILES 4\n\nBlockTexturePack::~BlockTexturePack() {\n    dispose();\n}\n\nvoid BlockTexturePack::init(ui32 resolution, ui32 maxTextures) {\n    m_resolution = resolution;\n    m_pageWidthPixels = m_resolution * m_stitcher.getTilesPerRow();\n    m_maxTextures = maxTextures;\n    m_textures = new BlockTexture[maxTextures];\n    m_nextFree = 0;\n    // Calculate max mipmap level\n    m_mipLevels = 0;\n    ui32 width = m_pageWidthPixels;\n    while (width > m_stitcher.getTilesPerRow()) {\n        width >>= 1;\n        m_mipLevels++;\n    }\n\n    // Set up first page for default textures\n    flagDirtyPage(0);\n\n    // Allocate biome and liquid maps and init to white\n    BlockColorMap& bmap = m_colorMaps[\"biome\"];\n    memset(bmap.pixels, 255, sizeof(bmap.pixels));\n    BlockColorMap& lmap = m_colorMaps[\"liquid\"];\n    memset(lmap.pixels, 255, sizeof(lmap.pixels));\n\n    SpaceSystemAssemblages::onAddSphericalVoxelComponent += makeDelegate(this, &BlockTexturePack::onAddSphericalVoxelComponent);\n}\n\n// TODO(Ben): Lock?\nBlockTextureIndex BlockTexturePack::addLayer(const BlockTextureLayer& layer, const nString& path, color4* pixels) {\n    BlockTextureIndex rv = 0;\n    // Map the texture\n    int firstPageIndex;\n    int lastPageIndex;\n    switch (layer.method) {\n        case ConnectedTextureMethods::CONNECTED:\n            rv = m_stitcher.mapContiguous(CONNECTED_TILES);\n            lastPageIndex = (rv + CONNECTED_TILES) / m_stitcher.getTilesPerPage();\n            break;\n        case ConnectedTextureMethods::RANDOM:\n            rv = m_stitcher.mapContiguous(layer.numTiles);\n            lastPageIndex = (rv + layer.numTiles) / m_stitcher.getTilesPerPage();\n            break;\n        case ConnectedTextureMethods::REPEAT:\n            rv = m_stitcher.mapBox(layer.size.x, layer.size.y);\n            lastPageIndex = (rv + (layer.size.y - 1) * m_stitcher.getTilesPerRow() + (layer.size.x - 1)) / m_stitcher.getTilesPerPage();\n            break;\n        case ConnectedTextureMethods::GRASS:\n            rv = m_stitcher.mapContiguous(GRASS_TILES);\n            lastPageIndex = (rv + GRASS_TILES) / m_stitcher.getTilesPerPage();\n            break;\n        case ConnectedTextureMethods::HORIZONTAL:\n            rv = m_stitcher.mapContiguous(HORIZONTAL_TILES);\n            lastPageIndex = (rv + HORIZONTAL_TILES) / m_stitcher.getTilesPerPage();\n            break;\n        case ConnectedTextureMethods::VERTICAL:\n            rv = m_stitcher.mapContiguous(VERTICAL_TILES);\n            lastPageIndex = (rv + VERTICAL_TILES) / m_stitcher.getTilesPerPage();\n            break;\n        case ConnectedTextureMethods::FLORA:\n            rv = m_stitcher.mapContiguous(layer.numTiles);\n            lastPageIndex = (rv + layer.numTiles) / m_stitcher.getTilesPerPage();\n            break;\n        default:\n            rv = m_stitcher.mapSingle();\n            lastPageIndex = (rv + 1) / m_stitcher.getTilesPerPage();\n            break;\n    }\n    firstPageIndex = rv / m_stitcher.getTilesPerPage();\n    flagDirtyPage(firstPageIndex);\n    if (lastPageIndex != firstPageIndex) flagDirtyPage(lastPageIndex);\n\n    // Copy data\n    switch (layer.method) {\n        case ConnectedTextureMethods::CONNECTED:\n            writeToAtlasContiguous(rv, pixels, 12, 4, CONNECTED_TILES);\n            break;\n        case ConnectedTextureMethods::RANDOM:\n            writeToAtlasContiguous(rv, pixels, layer.numTiles, 1, layer.numTiles);\n            break;\n        case ConnectedTextureMethods::REPEAT:\n            writeToAtlas(rv, pixels, m_resolution * layer.size.x, m_resolution * layer.size.y, 1);\n            break;\n        case ConnectedTextureMethods::GRASS:\n            writeToAtlasContiguous(rv, pixels, 3, 3, GRASS_TILES);\n            break;\n        case ConnectedTextureMethods::HORIZONTAL:\n            writeToAtlasContiguous(rv, pixels, HORIZONTAL_TILES, 1, HORIZONTAL_TILES);\n            break;\n        case ConnectedTextureMethods::VERTICAL:\n            writeToAtlasContiguous(rv, pixels, 1, VERTICAL_TILES, VERTICAL_TILES);\n            break;\n        case ConnectedTextureMethods::FLORA:\n            writeToAtlasContiguous(rv, pixels, layer.size.x, layer.size.y, layer.numTiles);\n            break;\n        default:\n            writeToAtlas(rv, pixels, m_resolution, m_resolution, 1);\n            break;\n    }\n\n    // Cache the texture description\n    AtlasTextureDescription tex;\n    tex.index = rv;\n    tex.size = layer.size;\n    tex.temp = layer;\n    m_descLookup[path] = tex;\n    return rv;\n}\n\nAtlasTextureDescription BlockTexturePack::findLayer(const nString& filePath) {\n    auto it = m_descLookup.find(filePath);\n    if (it != m_descLookup.end()) {\n        return it->second;\n    }\n    return {};\n}\n\nBlockTexture* BlockTexturePack::findTexture(const nString& filePath) {\n    auto it = m_textureLookup.find(filePath);\n    if (it != m_textureLookup.end()) {\n        return &m_textures[it->second];\n    }\n    return nullptr;\n}\n// Returns a pointer to the next free block texture and increments internal counter.\n// Will crash if called more than m_maxTextures times.\nBlockTexture* BlockTexturePack::getNextFreeTexture(const nString& filePath) {\n    if (m_nextFree >= m_maxTextures) pError(\"m_nextFree >= m_maxTextures in BlockTexturePack::getNextFreeTexture\");\n    m_textureLookup[filePath] = m_nextFree;\n    return &m_textures[m_nextFree++];\n}\n\nBlockColorMap* BlockTexturePack::getColorMap(const nString& path) {\n    auto it = m_colorMaps.find(path);\n    if (it != m_colorMaps.end()) return &it->second;\n    return nullptr;\n}\n\nBlockColorMap* BlockTexturePack::setColorMap(const nString& name, const vg::BitmapResource* rs) {\n    // Error check\n    if (rs->width != BLOCK_COLOR_MAP_WIDTH || rs->height != BLOCK_COLOR_MAP_WIDTH) {\n        fprintf(stderr, \"Warning: Color map %s is not %d x %d\\n\", name.c_str(), BLOCK_COLOR_MAP_WIDTH, BLOCK_COLOR_MAP_WIDTH);\n        fflush(stderr);\n    }\n    return setColorMap(name, rs->bytesUI8v3);\n}\n\nBlockColorMap* BlockTexturePack::setColorMap(const nString& name, const ui8v3* pixels) {\n    // Allocate the color map\n    BlockColorMap* colorMap = &m_colorMaps[name];\n    // Set its pixels\n    for (int y = 0; y < BLOCK_COLOR_MAP_WIDTH; y++) {\n        for (int x = 0; x < BLOCK_COLOR_MAP_WIDTH; x++) {\n            colorMap->pixels[y][x].r = pixels[y * BLOCK_COLOR_MAP_WIDTH + x].r;\n            colorMap->pixels[y][x].g = pixels[y * BLOCK_COLOR_MAP_WIDTH + x].g;\n            colorMap->pixels[y][x].b = pixels[y * BLOCK_COLOR_MAP_WIDTH + x].b;\n        }\n    }\n    return colorMap;\n}\n\nvoid BlockTexturePack::update() {\n    bool needsMipmapGen = false;\n    if (m_needsRealloc) {\n        allocatePages();\n        m_needsRealloc = false;\n        needsMipmapGen = true;\n        // Upload all pages\n        glBindTexture(GL_TEXTURE_2D_ARRAY, m_atlasTexture);\n        for (size_t i = 0; i < m_pages.size(); i++) {\n            uploadPage(i);\n        }\n        std::vector<int>().swap(m_dirtyPages);\n    } else if (m_dirtyPages.size()) {\n        needsMipmapGen = true;\n        // Upload dirty pages\n        glBindTexture(GL_TEXTURE_2D_ARRAY, m_atlasTexture);\n        for (auto& i : m_dirtyPages) {\n            uploadPage(i);\n        }\n        std::vector<int>().swap(m_dirtyPages);\n    }\n\n    if (needsMipmapGen) {\n        glGenerateMipmap(GL_TEXTURE_2D_ARRAY);\n        glBindTexture(GL_TEXTURE_2D_ARRAY, 0);\n    }\n}\n\nvoid BlockTexturePack::writeDebugAtlases() {\n    int width = m_resolution * m_stitcher.getTilesPerRow();\n    int height = width;\n\n    int pixelsPerPage = width * height * 4;\n    ui8 *pixels = new ui8[width * height * 4 * m_pages.size()];\n\n    glBindTexture(GL_TEXTURE_2D_ARRAY, m_atlasTexture);\n    glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);\n    for (size_t i = 0; i < m_pages.size(); i++) {\n        SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(pixels + i * pixelsPerPage, width, height, m_resolution, 4 * width, 0xFF, 0xFF00, 0xFF0000, 0x0);\n        SDL_SaveBMP(surface, (\"atlas\" + std::to_string(i) + \".bmp\").c_str());\n    }\n    glBindTexture(GL_TEXTURE_2D_ARRAY, 0);\n\n    delete[] pixels;\n}\n\nvoid BlockTexturePack::dispose() {\n    if (m_atlasTexture) glDeleteTextures(1, &m_atlasTexture);\n    m_atlasTexture = 0;\n    for (auto& p : m_pages) {\n        delete[] p.pixels;\n    }\n    std::vector<AtlasPage>().swap(m_pages);\n    m_stitcher.dispose();\n    std::map<nString, ui32>().swap(m_textureLookup);\n    m_nextFree = 0;\n    delete[] m_textures;\n    m_textures = nullptr;\n\n    SpaceSystemAssemblages::onAddSphericalVoxelComponent -= makeDelegate(this, &BlockTexturePack::onAddSphericalVoxelComponent);\n}\n\nnString getName(nString name) {\n    if (name.empty()) return \"\";\n    vio::Path p(name);\n    name = p.getLeaf();\n    while (name.back() != '.') name.pop_back();\n    name.pop_back();\n    return name;\n}\n\nvoid BlockTexturePack::flagDirtyPage(ui32 pageIndex) {\n    // If we need to allocate new pages, do so\n    if (pageIndex >= m_pages.size()) {\n        size_t i = m_pages.size();\n        m_pages.resize(pageIndex + 1);\n        for (; i < m_pages.size(); i++) {\n            m_pages[i].pixels = new color4[m_pageWidthPixels * m_pageWidthPixels];\n            memset(m_pages[i].pixels, 0, m_pageWidthPixels * m_pageWidthPixels * sizeof(color4));\n        }\n        m_needsRealloc = true;    \n    }\n    m_pages[pageIndex].dirty = true;\n}\n\nvoid BlockTexturePack::allocatePages() {\n    // Set up the storage\n    if (!m_atlasTexture) glGenTextures(1, &m_atlasTexture);\n    glBindTexture(GL_TEXTURE_2D_ARRAY, m_atlasTexture);\n\n    // Set up all the mipmap storage\n    ui32 width = m_pageWidthPixels;\n    for (ui32 i = 0; i < m_mipLevels; i++) {\n        glTexImage3D(GL_TEXTURE_2D_ARRAY, i, GL_RGBA8, width, width, m_pages.size(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);\n        width >>= 1;\n        if (width < 1) width = 1;\n    }\n\n    // Set up tex parameters\n    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, (int)m_mipLevels);\n    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LOD, (int)m_mipLevels);\n    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);\n    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);\n    \n    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);\n   \n    // Anisotropic filtering\n    float anisotropy;\n    glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy);\n    glActiveTexture(GL_TEXTURE0);\n    // Smooth texture params\n//    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n //   glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);\n //   glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);\n\n    // Unbind\n    glBindTexture(GL_TEXTURE_2D_ARRAY, 0);\n\n    // Check if we had any errors\n    checkGlError(\"BlockTexturePack::allocatePages\");\n}\n\nvoid BlockTexturePack::uploadPage(ui32 pageIndex) {\n    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, pageIndex, m_pageWidthPixels, m_pageWidthPixels, 1, GL_RGBA, GL_UNSIGNED_BYTE, m_pages[pageIndex].pixels);\n}\n\nvoid BlockTexturePack::writeToAtlas(BlockTextureIndex texIndex, color4* pixels, ui32 pixelWidth, ui32 pixelHeight, ui32 tileWidth) {\n\n    // Get the location in the array\n    ui32 i = texIndex % m_stitcher.getTilesPerPage();\n    ui32 dx = i % m_stitcher.getTilesPerRow();\n    ui32 dy = i / m_stitcher.getTilesPerRow();\n    ui32 pageIndex = texIndex / m_stitcher.getTilesPerPage();\n\n    // Temp variables to reduce multiplications\n    ui32 destOffset;\n    ui32 pixelsOffset;\n    ui32 yDestOffset;\n    ui32 yPixelsOffset;\n    ui32 pixelsPerRow = pixelWidth * tileWidth;\n\n    // Start of destination\n    color4* dest = m_pages[pageIndex].pixels + dx * m_resolution + dy * m_resolution * m_pageWidthPixels;\n    float alpha;\n\n    // Copy the block of pixels\n    for (ui32 y = 0; y < pixelHeight; y++) {\n        // Calculate Y offsets\n        yDestOffset = y * m_pageWidthPixels;\n        yPixelsOffset = y * pixelsPerRow;\n        // Need to do alpha blending for every pixel against a black background\n        for (ui32 x = 0; x < pixelWidth; x++) {\n            // Calculate offsets\n            destOffset = yDestOffset + x;\n            pixelsOffset = yPixelsOffset + x;\n            // Convert 0-255 to 0-1 for alpha mult\n            alpha = (float)pixels[pixelsOffset].a / 255.0f;\n\n            // Set the colors. Add  + 0.01f to make sure there isn't any rounding error when we truncate\n            dest[destOffset].r = (ui8)((float)pixels[pixelsOffset].r * alpha + 0.01f); // R\n            dest[destOffset].g = (ui8)((float)pixels[pixelsOffset].g * alpha + 0.01f); // G\n            dest[destOffset].b = (ui8)((float)pixels[pixelsOffset].b * alpha + 0.01f); // B\n            dest[destOffset].a = pixels[pixelsOffset].a; // A \n        }\n    }\n}\n\nvoid BlockTexturePack::writeToAtlasContiguous(BlockTextureIndex texIndex, color4* pixels, ui32 width, ui32 height, ui32 numTiles) {\n    ui32 pixelsPerTileRow = m_resolution * m_resolution * width;\n\n    ui32 n = 0;\n    for (ui32 y = 0; y < height; y++) {\n        for (ui32 x = 0; x < width && n < numTiles; x++, n++) {\n            // Get pointer to source data\n            color4* src = pixels + y * pixelsPerTileRow + x * m_resolution;\n\n            writeToAtlas(texIndex++, src, m_resolution, m_resolution, width);\n        }\n    }\n}\n\nvoid BlockTexturePack::onAddSphericalVoxelComponent(Sender s VORB_MAYBE_UNUSED, SphericalVoxelComponent& cmp, vecs::EntityID e VORB_MAYBE_UNUSED) {\n    // Set color maps\n    // TODO(Ben): This assumes a single SVC!\n    if (cmp.planetGenData->terrainColorPixels.data) {\n        BlockColorMap* m = setColorMap(\"biome\", &cmp.planetGenData->terrainColorPixels);\n        // Set all layers\n        for (ui32 i = 0; i < m_nextFree; i++) {\n            if (m_textures[i].layers.base.colorMapPath == \"biome\") {\n                m_textures[i].layers.base.colorMap = m;\n            }\n            if (m_textures[i].layers.overlay.colorMapPath == \"biome\") {\n                m_textures[i].layers.overlay.colorMap = m;\n            }\n        }\n    }\n    if (cmp.planetGenData->liquidColorMap.id) {\n        BlockColorMap* m = setColorMap(\"liquid\", &cmp.planetGenData->liquidColorPixels);\n        // Set all layers\n        for (ui32 i = 0; i < m_nextFree; i++) {\n                if (m_textures[i].layers.base.colorMapPath == \"liquid\") {\n                    m_textures[i].layers.base.colorMap = m;\n                }\n                if (m_textures[i].layers.overlay.colorMapPath == \"liquid\") {\n                    m_textures[i].layers.overlay.colorMap = m;\n                }\n        }\n    }\n}"
  },
  {
    "path": "SoA/BlockTexturePack.h",
    "content": "///\n/// BlockTexturePack.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 16 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// A texture pack for blocks\n///\n\n#pragma once\n\n#ifndef BlockTexturePack_h__\n#define BlockTexturePack_h__\n\n#include \"BlockTexture.h\"\n\n#include <map>\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/voxel/VoxelTextureStitcher.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/ecs/Entity.h>\n\nstruct SphericalVoxelComponent;\n\nDECL_VG(class BitmapResource; class Texture);\n\nstruct AtlasTextureDescription {\n    BlockTextureLayer temp;\n    BlockTextureIndex index;\n    ui32v2 size;\n};\n\n#define BLOCK_COLOR_MAP_WIDTH 256\n\nstruct BlockColorMap {\n    color3 pixels[BLOCK_COLOR_MAP_WIDTH][BLOCK_COLOR_MAP_WIDTH];\n};\n\nclass BlockTexturePack {\npublic:\n    BlockTexturePack():\n    m_atlasTexture(0),\n    m_resolution(0),\n    m_pageWidthPixels(0),\n    m_mipLevels(0),\n    m_needsRealloc(false),\n    m_textures(nullptr),\n    m_nextFree(0),\n    m_maxTextures(0)\n    {}\n\n    ~BlockTexturePack();\n\n    void init(ui32 resolution, ui32 maxTextures);\n    // Maps the texture layer to the atlas and updates the index in layer.\n    // Does not check if texture already exists\n    BlockTextureIndex addLayer(const BlockTextureLayer& layer, const nString& path, color4* pixels);\n    // Tries to find the texture index. Returns empty description on fail.\n    AtlasTextureDescription findLayer(const nString& filePath);\n\n    BlockTexture* findTexture(const nString& filePath);\n    // Returns a pointer to the next free block texture and increments internal counter.\n    // Will crash if called more than m_maxTextures times.\n    BlockTexture* getNextFreeTexture(const nString& filePath);\n\n    BlockTexture* getDefaultTexture() { return &m_defaultTexture; }\n\n    // Gets existing color map or loads from file\n    BlockColorMap* getColorMap(const nString& path);\n\n    BlockColorMap* setColorMap(const nString& name, const vg::BitmapResource* rs);\n    BlockColorMap* setColorMap(const nString& name, const ui8v3* pixels);\n\n    // Call on GL thread. Will upload any textures that aren't yet uploaded.\n    void update();\n\n    void writeDebugAtlases();\n\n    void dispose();\n\n    const VGTexture& getAtlasTexture() const { return m_atlasTexture; }\n    const ui32& getResolution() const { return m_resolution; }\nprivate:\n    VORB_NON_COPYABLE(BlockTexturePack);\n\n    void flagDirtyPage(ui32 pageIndex);\n\n    void allocatePages();\n\n    void uploadPage(ui32 pageIndex);\n\n    void writeToAtlas(BlockTextureIndex texIndex, color4* pixels, ui32 pixelWidth, ui32 pixelHeight, ui32 tileWidth);\n\n    void writeToAtlasContiguous(BlockTextureIndex texIndex, color4* pixels, ui32 width, ui32 height, ui32 numTiles);\n\n    /************************************************************************/\n    /* Event Handlers                                                       */\n    /************************************************************************/\n    void onAddSphericalVoxelComponent(Sender s, SphericalVoxelComponent& cmp, vecs::EntityID e);\n\n    struct AtlasPage {\n        AtlasPage():pixels(nullptr), dirty(true){}\n        color4* pixels;\n        bool dirty;\n    };\n\n    vvox::VoxelTextureStitcher m_stitcher;\n\n    VGTexture m_atlasTexture;\n    std::vector<AtlasPage> m_pages; ///< Cached pixel data\n    std::vector<int> m_dirtyPages; ///< List of dirty pages TODO(Ben): Maybe bad for multithreading\n    std::unordered_map<nString, AtlasTextureDescription> m_descLookup;\n    ui32 m_resolution;\n    ui32 m_pageWidthPixels;\n    ui32 m_mipLevels;\n    bool m_needsRealloc;\n\n    // For cache friendly caching of textures\n    std::map<nString, ui32> m_textureLookup;\n    std::map<nString, BlockColorMap> m_colorMaps;\n    BlockTexture* m_textures; ///< Storage of all block textures\n    BlockTexture m_defaultTexture;\n    ui32 m_nextFree;\n    ui32 m_maxTextures; ///< Maximum possible number of unique textures with this mod config\n};\n\n#endif // BlockTexturePack_h__"
  },
  {
    "path": "SoA/BloomRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"BloomRenderStage.h\"\n\n#include <sstream>\n#include <Vorb/graphics/GLRenderTarget.h>\n#include <Vorb/graphics/GLProgram.h>\n#include \"ShaderLoader.h\"\n#include \"LoadContext.h\"\n#include \"Errors.h\"\n#include \"Vorb/ui/GameWindow.h\"\n\n#define TASK_WORK  4                     // (arbitrary) weight of task\n#define TOTAL_TASK 4                    // number of tasks\n#define TOTAL_WORK TOTAL_TASK * TASK_WORK\n\n#define BLOOM_TEXTURE_SLOT_COLOR  0      // texture slot to bind color texture which luma info will be extracted\n#define BLOOM_TEXTURE_SLOT_LUMA   0       // texture slot to bind luma texture\n#define BLOOM_TEXTURE_SLOT_BLUR   1       // texture slot to bind blur texture\n\nfloat BloomRenderStage::gauss(int i, float sigma2) {\n    return 1.0 / std::sqrt(2 * 3.14159265 * sigma2) * std::exp(-(i*i) / (2 * sigma2));\n}\n\nvoid BloomRenderStage::init(vui::GameWindow* window, StaticLoadContext& context) {\n\n    IRenderStage::init(window, context);\n    context.addAnticipatedWork(TOTAL_WORK, TOTAL_TASK);\n\n    // initialize FBOs\n    m_fbo1.setSize(m_window->getWidth(), m_window->getHeight());\n    m_fbo2.setSize(m_window->getWidth(), m_window->getHeight());\n    m_fbo1.init(vorb::graphics::TextureInternalFormat::RGBA32F, 0, vorb::graphics::TextureFormat::RGBA, vorb::graphics::TexturePixelType::FLOAT);\n    m_fbo2.init(vorb::graphics::TextureInternalFormat::RGBA32F, 0, vorb::graphics::TextureFormat::RGBA, vorb::graphics::TexturePixelType::FLOAT);\n\n}\n\nvoid BloomRenderStage::setParams(ui32 gaussianN /* = 20 */, float gaussianVariance /* = 36.0f */, float lumaThreshold /* = 0.75f */) {\n    if (gaussianN > 50)\n        // if a bigger radius than 50 is desired, change the size of weights array in this file and the blur shaders\n        throw \"Gaussian Radius for BloomRenderStage::setParams has to be less than 50.\";\n    m_gaussianN = gaussianN;\n    m_gaussianVariance = gaussianVariance;\n    m_lumaThreshold = lumaThreshold;\n}\n\nvoid BloomRenderStage::load(StaticLoadContext& context) {\n\n    // luma\n    context.addTask([&](Sender, void*) {\n        m_programLuma = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\", \"Shaders/PostProcessing/BloomLuma.frag\");\n        m_programLuma.use();\n        glUniform1i(m_programLuma.getUniform(\"unTexColor\"), BLOOM_TEXTURE_SLOT_COLOR);\n        glUniform1f(m_programLuma.getUniform(\"unLumaThresh\"), m_lumaThreshold);\n        m_programLuma.unuse();\n\n        context.addWorkCompleted(TOTAL_TASK);\n    }, false);\n\n    // gaussian first pass\n    context.addTask([&](Sender, void*) {\n        m_programGaussianFirst = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\", \"Shaders/PostProcessing/BloomGaussianFirst.frag\");\n        m_programGaussianFirst.use();\n        glUniform1i(m_programGaussianFirst.getUniform(\"unTexLuma\"), BLOOM_TEXTURE_SLOT_LUMA);\n        glUniform1i(m_programGaussianFirst.getUniform(\"unHeight\"), m_window->getHeight());\n        glUniform1i(m_programGaussianFirst.getUniform(\"unGaussianN\"), m_gaussianN);\n        m_programGaussianFirst.unuse();\n        context.addWorkCompleted(TOTAL_TASK);\n    }, true);\n\n    // gaussian second pass\n    context.addTask([&](Sender, void*) {\n        m_programGaussianSecond = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\", \"Shaders/PostProcessing/BloomGaussianSecond.frag\");\n        m_programGaussianSecond.use();\n        glUniform1i(m_programGaussianSecond.getUniform(\"unTexColor\"), BLOOM_TEXTURE_SLOT_COLOR);\n        glUniform1i(m_programGaussianSecond.getUniform(\"unTexBlur\"), BLOOM_TEXTURE_SLOT_BLUR);\n        glUniform1i(m_programGaussianSecond.getUniform(\"unWidth\"), m_window->getWidth());\n        glUniform1i(m_programGaussianSecond.getUniform(\"unGaussianN\"), m_gaussianN);\n        m_programGaussianSecond.unuse();\n        context.addWorkCompleted(TOTAL_TASK);\n    }, true);\n\n    // calculate gaussian weights\n\n    context.addTask([&](Sender, void*) {\n        float weights[50], sum;\n        weights[0] = gauss(0, m_gaussianVariance);\n        sum = weights[0];\n        for (ui32 i = 1; i < m_gaussianN; i++) {\n            weights[i] = gauss(i, m_gaussianVariance);\n            sum += 2 * weights[i];\n        }\n        for (ui32 i = 0; i < m_gaussianN; i++) {\n            weights[i] = weights[i] / sum;\n        }\n        m_programGaussianFirst.use();\n        glUniform1fv(m_programGaussianFirst.getUniform(\"unWeight[0]\"), m_gaussianN, weights);\n        m_programGaussianFirst.unuse();\n        m_programGaussianSecond.use();\n        glUniform1fv(m_programGaussianSecond.getUniform(\"unWeight[0]\"), m_gaussianN, weights);\n        m_programGaussianSecond.unuse();\n\n        context.addWorkCompleted(TOTAL_TASK);\n    }, false);\n}\n\nvoid BloomRenderStage::hook(vg::FullQuadVBO* quad) {\n    m_quad = quad;\n}\n\nvoid BloomRenderStage::dispose(StaticLoadContext& context VORB_MAYBE_UNUSED) {\n    m_programLuma.dispose();\n    m_programGaussianFirst.dispose();\n    m_programGaussianSecond.dispose();\n}\n\nvoid BloomRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    // get initial bound FBO and bound color texture to use it on final pass\n    GLint initial_fbo, initial_texture;\n    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &initial_fbo);\n    glGetIntegerv(GL_TEXTURE_BINDING_2D, &initial_texture);\n\n    // color texture should be bound on GL_TEXTURE0 slot\n\n    // luma pass rendering on temporary FBO 1\n    m_fbo1.use();\n    glActiveTexture(GL_TEXTURE0 + BLOOM_TEXTURE_SLOT_COLOR);\n    glBindTexture(GL_TEXTURE_2D, initial_texture);\n    render(BLOOM_RENDER_STAGE_LUMA);\n    m_fbo1.unuse(m_window->getWidth(), m_window->getHeight());\n\n    // first gaussian blur pass rendering on temporary FBO 2\n    m_fbo2.use();\n    glActiveTexture(GL_TEXTURE0 + BLOOM_TEXTURE_SLOT_LUMA);\n    m_fbo1.bindTexture();\n    render(BLOOM_RENDER_STAGE_GAUSSIAN_FIRST);\n    m_fbo2.unuse(m_window->getWidth(), m_window->getHeight());\n\n    // second gaussian blur pass rendering on initially FBO\n    glActiveTexture(GL_TEXTURE0 + BLOOM_TEXTURE_SLOT_COLOR);\n    glBindTexture(GL_TEXTURE_2D, initial_texture);\n    glActiveTexture(GL_TEXTURE0 + BLOOM_TEXTURE_SLOT_BLUR);\n    m_fbo2.bindTexture();\n    glBindFramebuffer(GL_FRAMEBUFFER, initial_fbo);\n    render(BLOOM_RENDER_STAGE_GAUSSIAN_SECOND);\n}\n\nvoid BloomRenderStage::render(BloomRenderStagePass stage) {\n    switch (stage) {\n        // luma\n    case BLOOM_RENDER_STAGE_LUMA:\n        m_programLuma.use();\n        m_programLuma.enableVertexAttribArrays();\n\n        glDisable(GL_DEPTH_TEST);\n        m_quad->draw();\n        glEnable(GL_DEPTH_TEST);\n\n        m_programLuma.disableVertexAttribArrays();\n        m_programLuma.unuse();\n        break;\n\n        // first gaussian pass\n    case BLOOM_RENDER_STAGE_GAUSSIAN_FIRST:\n        m_programGaussianFirst.use();\n        m_programGaussianFirst.enableVertexAttribArrays();\n\n        glDisable(GL_DEPTH_TEST);\n        m_quad->draw();\n        glEnable(GL_DEPTH_TEST);\n\n        m_programGaussianFirst.disableVertexAttribArrays();\n        m_programGaussianFirst.unuse();\n        break;\n\n        // second gaussian pass\n    case BLOOM_RENDER_STAGE_GAUSSIAN_SECOND:\n        m_programGaussianSecond.use();\n        m_programGaussianSecond.enableVertexAttribArrays();\n\n        glDisable(GL_DEPTH_TEST);\n        m_quad->draw();\n        glEnable(GL_DEPTH_TEST);\n\n        m_programGaussianSecond.disableVertexAttribArrays();\n        m_programGaussianSecond.unuse();\n        break;\n    }\n\n}\n\n"
  },
  {
    "path": "SoA/BloomRenderStage.h",
    "content": "/// \n///  BloomRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Isaque Dutra on 2 June 2015\n///  Copyright 2015 Regrowth Studios\n///  MIT License\n///  \n///  This file implements a bloom render stage for\n///  MainMenuRenderer.\n///\n\n#pragma once\n\n#ifndef BloomRenderStage_h__\n#define BloomRenderStage_h__\n\n#include <Vorb/graphics/GLRenderTarget.h>\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GLProgram.h>\n#include \"ShaderLoader.h\"\n#include \"LoadContext.h\"\n\n#include \"IRenderStage.h\"\n\n\ntypedef enum {\n    BLOOM_RENDER_STAGE_LUMA,\n    BLOOM_RENDER_STAGE_GAUSSIAN_FIRST,\n    BLOOM_RENDER_STAGE_GAUSSIAN_SECOND\n} BloomRenderStagePass;\n\nclass BloomRenderStage : public IRenderStage {\npublic:\n\n    void init(vui::GameWindow* window, StaticLoadContext& context) override;\n\n    void setParams(ui32 gaussianN = 20, float gaussianVariance = 36.0f, float lumaThreshold = 0.75f);\n\n    void load(StaticLoadContext& context) override;\n\n    void hook(vg::FullQuadVBO* quad);\n\n    void dispose(StaticLoadContext& context) override;\n\n    /// Draws the render stage\n    void render(const Camera* camera = nullptr) override;\n\nprivate:\n    float gauss(int i, float sigma2);\n    void render(BloomRenderStagePass stage);\n\n    vg::GLProgram m_programLuma, m_programGaussianFirst, m_programGaussianSecond;\n    vg::FullQuadVBO* m_quad;    ///< For use in processing through data\n    vg::GLRenderTarget m_fbo1, m_fbo2;\n    ui32 m_gaussianN;           ///< Threshold for filtering image luma for bloom bluring\n    float m_gaussianVariance;  ///< Radius number for gaussian blur. Must be less than 50.\n    float m_lumaThreshold;     ///< Gaussian variance for blur pass\n};\n\n#endif // BloomRenderStage_h__"
  },
  {
    "path": "SoA/CAEngine.cpp",
    "content": "#include \"stdafx.h\"\n#include \"CAEngine.h\"\n\n#include <Vorb/io/IOManager.h>\n\n#include \"BlockPack.h\"\n#include \"Chunk.h\"\n#include \"ChunkUpdater.h\"\n#include \"GameManager.h\"\n#include \"VoxelUtils.h\"\n\n// TODO: Do we want this as is? If so reimplement and remove VORB_UNUSED tags.\n\nCaPhysicsTypeDict CaPhysicsType::typesCache;\nCaPhysicsTypeList CaPhysicsType::typesArray;\n\nKEG_ENUM_DEF(CAAlgorithm, CAAlgorithm, kt) {\n    kt.addValue(\"none\", CAAlgorithm::NONE);\n    kt.addValue(\"liquid\", CAAlgorithm::LIQUID);\n    kt.addValue(\"powder\", CAAlgorithm::POWDER);\n}\n\nKEG_TYPE_DEF_SAME_NAME(CaPhysicsData, kt) {\n    kt.addValue(\"updateRate\", keg::Value::basic(offsetof(CaPhysicsData, updateRate), keg::BasicType::UI32));\n    kt.addValue(\"liquidLevels\", keg::Value::basic(offsetof(CaPhysicsData, liquidLevels), keg::BasicType::UI32));\n    kt.addValue(\"algorithm\", keg::Value::custom(offsetof(CaPhysicsData, alg), \"CA_ALGORITHM\", true));\n}\n\nbool CaPhysicsType::update() {\n    _ticks++;\n    if (_ticks == _data.updateRate * HALF_CA_TICK_RES) {\n        _ticks = 0;\n        _isEven = !_isEven;\n        return true;\n    }\n    return false;\n}\n\nbool CaPhysicsType::loadFromYml(const nString& filePath, const vio::IOManager* ioManager) {\n    // Load the file\n    nString fileData;\n    ioManager->readFileToString(filePath.c_str(), fileData);\n    if (fileData.length()) {\n        if (keg::parse(&_data, fileData.c_str(), \"CaPhysicsData\") == keg::Error::NONE) {\n            CaPhysicsType::typesCache[filePath] = this;\n            _caIndex = typesArray.size();\n            typesArray.push_back(this);\n        } else {\n            return false;\n        }\n    } else {\n        return false;\n    }\n    return true;\n}\n\nvoid CaPhysicsType::clearTypes() {\n    // Clear CA physics cache\n    for (auto& it : CaPhysicsType::typesCache) {\n        delete it.second;\n    }\n    CaPhysicsType::typesCache.clear();\n    typesArray.clear();\n}\n\nCAEngine::CAEngine(ChunkManager* chunkManager VORB_UNUSED, PhysicsEngine* physicsEngine VORB_UNUSED) :\n    _chunk(nullptr)\n//    m_chunkManager(chunkManager),\n//    m_physicsEngine(physicsEngine)\n{\n    memset(_blockUpdateFlagList, 0, sizeof(_blockUpdateFlagList));\n    //temporary\n    _lowIndex = 0; // TODO(Ben): yeahhhhhh....\n    _range = 100;\n    _highIndex = _lowIndex + _range - 1;\n}\n\nvoid CAEngine::updateSpawnerBlocks(bool powders VORB_UNUSED)\n{\n    //_lockedChunk = nullptr;\n    //int spawnerVal;\n    //int sinkVal;\n    //int c;\n    //f64v3 physicsBlockPos;\n    //std::vector <GLushort> &activeBlocks = _chunk->spawnerBlocks;\n\n    //Chunk *bottom = _chunk->bottom;\n\n    //for (size_t i = 0; i < activeBlocks.size();){\n    //    c = activeBlocks[i];\n\n    //    const Block &block = _chunk->getBlock(c);\n\n    //    spawnerVal = block.spawnerVal;\n    //    sinkVal = block.sinkVal;\n    //    if (spawnerVal == 0 && sinkVal == 0){\n    //        activeBlocks[i] = activeBlocks.back();\n    //        activeBlocks.pop_back();\n    //        continue;\n    //    }\n    //    if (spawnerVal){\n    //        if (vvox::getBottomBlockData(_chunk, _lockedChunk, c) == 0){\n    //            if (c >= CHUNK_LAYER){\n    //                c = c - CHUNK_LAYER;\n    //                if (spawnerVal >= LOWWATER) {\n    //                    ChunkUpdater::placeBlock(_chunk, _lockedChunk, c, spawnerVal);\n    //                } else if (powders){\n    //                    physicsBlockPos = f64v3((double)_chunk->voxelPosition.x + c%CHUNK_WIDTH + 0.5, (double)_chunk->voxelPosition.y + c / CHUNK_LAYER, (double)_chunk->voxelPosition.z + (c%CHUNK_LAYER) / CHUNK_WIDTH + 0.5);\n    //                    m_physicsEngine->addPhysicsBlock(physicsBlockPos, spawnerVal);\n    //                }\n    //            } else if (bottom && bottom->isAccessible){\n    //                c = c - CHUNK_LAYER + CHUNK_SIZE;\n    //                if (spawnerVal >= LOWWATER){\n    //                    ChunkUpdater::placeBlockSafe(bottom, _lockedChunk, c, spawnerVal);\n    //                } else if (powders){\n    //                    physicsBlockPos = f64v3((double)bottom->voxelPosition.x + c%CHUNK_WIDTH + 0.5, (double)bottom->voxelPosition.y + c / CHUNK_LAYER, (double)bottom->voxelPosition.z + (c%CHUNK_LAYER) / CHUNK_WIDTH + 0.5);\n    //                    m_physicsEngine->addPhysicsBlock(physicsBlockPos, spawnerVal);\n    //                }\n    //            }\n    //        }\n    //    }\n    //    if (sinkVal){\n    //        if (GETBLOCKID(vvox::getTopBlockData(_chunk, _lockedChunk, c)) == sinkVal){\n    //            if (c + CHUNK_LAYER < CHUNK_SIZE){\n    //                c = c + CHUNK_LAYER;\n    //                _chunk->setBlockDataSafe(_lockedChunk, c, NONE); //TODO: This is incorrect, should call RemoveBlock or something similar\n    //                ChunkUpdater::addBlockToUpdateList(_chunk, _lockedChunk, c);\n    //                _chunk->changeState(ChunkStates::MESH);\n    //            } else if (_chunk->top && _chunk->top->isAccessible){\n    //                c = c + CHUNK_LAYER - CHUNK_SIZE;\n    //                _chunk->top->setBlockDataSafe(_lockedChunk, c, NONE);\n    //                ChunkUpdater::addBlockToUpdateList(_chunk->top, _lockedChunk, c);\n    //                _chunk->top->changeState(ChunkStates::MESH);\n    //            }\n    //        }\n    //    }\n    //    i++;\n    //}\n    //if (_lockedChunk) {\n    //    _lockedChunk->unlock();\n    //    _lockedChunk = nullptr;\n    //}\n}\n\nvoid CAEngine::updateLiquidBlocks(int caIndex VORB_UNUSED)\n{\n    //_lockedChunk = nullptr;\n    //vvox::swapLockedChunk(_chunk, _lockedChunk);\n    //std::vector<bool>& activeUpdateList = _chunk->activeUpdateList;\n    //std::vector <ui16> *blockUpdateList = &_chunk->blockUpdateList[caIndex << 1];\n    //int actv = activeUpdateList[caIndex];\n    //int size = blockUpdateList[actv].size(); \n    //if (size == 0) {\n    //    _lockedChunk->unlock();\n    //    _lockedChunk = nullptr;\n    //    return;\n    //}\n    //activeUpdateList[caIndex] = !(activeUpdateList[caIndex]); //switch to other list\n    //int c, blockID;\n    //Uint32 i;\n\n    //for (i = 0; i < blockUpdateList[actv].size(); i++){\n    //    c = blockUpdateList[actv][i];\n    //    if (_blockUpdateFlagList[c] == 0){\n    //        _usedUpdateFlagList.push_back(c);\n    //        _blockUpdateFlagList[c] = 1;\n    //        blockID = _chunk->getBlockID(c);\n    //        if (blockID >= _lowIndex) liquidPhysics(c, blockID);\n    //    }\n    //}\n    //blockUpdateList[actv].clear();\n\n    //for (Uint32 i = 0; i < _usedUpdateFlagList.size(); i++){\n    //    _blockUpdateFlagList[_usedUpdateFlagList[i]] = 0;\n    //}\n    //_usedUpdateFlagList.clear();\n    //if (_lockedChunk) {\n    //    _lockedChunk->unlock();\n    //    _lockedChunk = nullptr;\n    //}\n}\n\nvoid CAEngine::updatePowderBlocks(int caIndex VORB_UNUSED)\n{\n //   _lockedChunk = nullptr;\n //   std::vector<bool>& activeUpdateList = _chunk->activeUpdateList;\n //   std::vector <ui16> *blockUpdateList = &_chunk->blockUpdateList[caIndex << 1];\n //   int actv = activeUpdateList[caIndex];\n\n //   Uint32 size = blockUpdateList[actv].size();\n //   if (size != 0){\n //       activeUpdateList[caIndex] = !(activeUpdateList[caIndex]); //switch to other list\n //       int b;\n //       Uint32 i;\n\n //       for (i = 0; i < size; i++){ //powder\n //           b = blockUpdateList[actv][i];\n //           if (_blockUpdateFlagList[b] == 0){\n //               _usedUpdateFlagList.push_back(b);\n //               _blockUpdateFlagList[b] = 1;\n //               powderPhysics(b);\n //           }\n //       }\n\n //       blockUpdateList[actv].clear();\n\n //       for (i = 0; i < _usedUpdateFlagList.size(); i++){\n //           _blockUpdateFlagList[_usedUpdateFlagList[i]] = 0;\n //       }\n //       _usedUpdateFlagList.clear();\n //   }\n\n ////   blockUpdateList = _chunk->blockUpdateList[2];\n ////   actv = activeUpdateList[2];\n ////   size = blockUpdateList[actv].size();\n\n //   //if (size != 0){\n //   //    activeUpdateList[2] = !(activeUpdateList[2]);\n //   //    int b;\n //   //    Uint32 i;\n\n //   //    for (i = 0; i < size; i++){ //snow\n //   //        b = blockUpdateList[actv][i];\n //   //        if (_blockUpdateFlagList[b] == 0){\n //   //            _usedUpdateFlagList.push_back(b);\n //   //            _blockUpdateFlagList[b] = 1;\n //   //            if (_chunk->getBlock(b).physicsProperty == P_SNOW){ \n //   //                powderPhysics(b);\n //   //            }\n //   //        }\n //   //    }\n //   //    blockUpdateList[actv].clear(); \n\n //   //    for (i = 0; i < _usedUpdateFlagList.size(); i++){\n //   //        _blockUpdateFlagList[_usedUpdateFlagList[i]] = 0;\n //   //    }\n //   //    _usedUpdateFlagList.clear();\n //   //}\n //   if (_lockedChunk) {\n //       _lockedChunk->unlock();\n //       _lockedChunk = nullptr;\n //   }\n}\n\nvoid CAEngine::liquidPhysics(i32 startBlockIndex VORB_UNUSED, i32 startBlockID VORB_UNUSED) {\n    //// Helper function\n    //#define IS_LIQUID(b) ((b) >= _lowIndex && (b) < _highIndex)\n\n    //i32v3 pos = getPosFromBlockIndex(startBlockIndex);\n    //Chunk* owner;\n    //i32 nextIndex;\n    //i32 nextCoord;\n    //i32 blockID;\n    //i32 diff;\n    //i32 index = 0;\n    //Chunk* adjOwners[4] = {nullptr, nullptr, nullptr, nullptr};\n    //Chunk* adjAdjOwners[4] = { nullptr, nullptr, nullptr, nullptr };\n    //i32 adjIndices[4];\n    //i32 adjAdjIndices[4];\n    //i32 diffs[4];\n\n    //bool hasChanged = false;\n    //bool inFrustum = (!_chunk->mesh || _chunk->mesh->inFrustum);\n    //const i32v3 &position = _chunk->voxelPosition;\n\n    //// Get the block index and owner for the bottom chunk\n    //if (pos.y > 0){\n    //    nextIndex = startBlockIndex - CHUNK_LAYER;\n    //    owner = _chunk;\n    //} else if (_chunk->bottom && _chunk->bottom->isAccessible){\n    //    nextIndex = startBlockIndex + CHUNK_SIZE - CHUNK_LAYER;\n    //    owner = _chunk->bottom;\n    //} else{\n    //    return;\n    //}\n\n    ////Get the block ID\n    //blockID = owner->getBlockIDSafe(_lockedChunk, nextIndex);\n\n    ////If we are falling on an air block\n    //if (blockID == NONE){ \n    //    ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, startBlockID);\n    //    ChunkUpdater::removeBlockFromLiquidPhysicsSafe(_chunk, _lockedChunk, startBlockIndex);\n\n    //    ChunkUpdater::updateNeighborStates(_chunk, pos, ChunkStates::WATERMESH);\n    //    if (owner != _chunk) ChunkUpdater::updateNeighborStates(owner, nextIndex, ChunkStates::WATERMESH);\n\n    //    if (startBlockID > _lowIndex + 10 && inFrustum) particleEngine.addParticles(m_chunkManager, 1, f64v3(position.x + pos.x, position.y + pos.y - 1.0, position.z + pos.z), 0, 0.1, 16665, 1111, f32v4(255.0f, 255.0f, 255.0f, 255.0f), Blocks[blockID].particleTex, 0.5f, 8);\n    //    return;\n    //} else if (IS_LIQUID(blockID)) { //If we are falling on the same liquid\n    //    //how much empty space there is\n    //    diff = _highIndex - blockID;\n\n    //    //if we cant completely fill in the empty space, fill it in as best we can\n    //    if (startBlockID - _lowIndex + 1 > diff){\n    //        startBlockID -= diff;\n    //        ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, blockID + diff);\n\n    //        if (diff > 10 && inFrustum) particleEngine.addParticles(m_chunkManager, 1, f64v3(position.x + pos.x, position.y + pos.y - 1.0, position.z + pos.z), 0, 0.1, 16665, 1111, f32v4(255.0f, 255.0f, 255.0f, 255.0f), Blocks[blockID].particleTex, 0.5f, 8);\n    //        hasChanged = 1;\n    //        \n    //        if (owner != _chunk) {\n    //            owner->changeState(ChunkStates::WATERMESH);\n    //            ChunkUpdater::updateNeighborStates(owner, nextIndex, ChunkStates::WATERMESH);\n    //        }\n\n    //    } else { //otherwise ALL liquid falls and we are done\n    //        ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, blockID + (startBlockID - _lowIndex + 1));\n    //        ChunkUpdater::removeBlockFromLiquidPhysicsSafe(_chunk, _lockedChunk, startBlockIndex);\n\n    //        ChunkUpdater::updateNeighborStates(_chunk, pos, ChunkStates::WATERMESH);\n    //        if (owner != _chunk) ChunkUpdater::updateNeighborStates(owner, nextIndex, ChunkStates::WATERMESH);\n\n    //        if (startBlockID > _lowIndex + 10 && inFrustum) particleEngine.addParticles(m_chunkManager, 1, f64v3(position.x + pos.x, position.y + pos.y - 1.0, position.z + pos.z), 0, 0.1, 16665, 1111, f32v4(255.0f, 255.0f, 255.0f, 255.0f), Blocks[blockID].particleTex, 0.5f, 8);\n    //        return;\n    //    }\n    //} else if (Blocks[blockID].waterBreak) { //destroy a waterBreak block, such as flora\n    //    ChunkUpdater::removeBlock(m_chunkManager, m_physicsEngine, owner, _lockedChunk, nextIndex, true);\n    //    ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, startBlockID);\n    //    ChunkUpdater::removeBlockFromLiquidPhysicsSafe(_chunk, _lockedChunk, startBlockIndex);\n\n    //    ChunkUpdater::updateNeighborStates(_chunk, pos, ChunkStates::WATERMESH);\n    //    if (owner != _chunk) ChunkUpdater::updateNeighborStates(owner, nextIndex, ChunkStates::WATERMESH);\n\n    //    if (startBlockID > _lowIndex + 10 && inFrustum) particleEngine.addParticles(m_chunkManager, 1, f64v3(position.x + pos.x, position.y + pos.y - 1.0, position.z + pos.z), 0, 0.1, 16665, 1111, f32v4(255.0f, 255.0f, 255.0f, 255.0f), Blocks[blockID].particleTex, 0.5f, 8);\n    //    return;\n    //}\n\n    ////Left Direction\n    //if (pos.x > 0) {\n    //    nextIndex = startBlockIndex - 1;\n    //    owner = _chunk;\n    //    nextCoord = pos.x - 1;\n    //} else if (_chunk->left && _chunk->left->isAccessible) {\n    //    nextIndex = startBlockIndex - 1 + CHUNK_WIDTH;\n    //    owner = _chunk->left;\n    //    nextCoord = CHUNK_WIDTH - 1;\n    //} else {\n    //    return;\n    //}\n\n    //blockID = owner->getBlockIDSafe(_lockedChunk, nextIndex);\n\n    //if (blockID == NONE || Blocks[blockID].waterBreak){ //calculate diffs\n    //    diffs[index] = (startBlockID - (_lowIndex - 1));\n    //    adjOwners[index] = owner;\n    //    adjIndices[index++] = nextIndex;\n    //} else if (IS_LIQUID(blockID)){ //tmp CANT FLOW THOUGH FULL WATER\n    //    \n    //    if (nextCoord > 0){ //extra flow. its the secret!\n    //        adjAdjIndices[index] = nextIndex - 1;\n    //        adjAdjOwners[index] = owner;\n    //    } else if (owner->left && owner->left->isAccessible){\n    //        adjAdjIndices[index] = nextIndex + CHUNK_WIDTH - 1;\n    //        adjAdjOwners[index] = owner->left;\n    //    }\n    //    diffs[index] = (startBlockID - blockID);\n    //    adjOwners[index] = owner;\n    //    adjIndices[index++] = nextIndex;\n    //}\n\n    ////Back Direction\n    //if (pos.z > 0) {\n    //    nextIndex = startBlockIndex - CHUNK_WIDTH;\n    //    owner = _chunk;\n    //    nextCoord = pos.z - 1;\n    //} else if (_chunk->back && _chunk->back->isAccessible) {\n    //    nextIndex = startBlockIndex - CHUNK_WIDTH + CHUNK_LAYER;\n    //    owner = _chunk->back;\n    //    nextCoord = CHUNK_WIDTH - 1;\n    //} else {\n    //    return;\n    //}\n\n    //blockID = owner->getBlockIDSafe(_lockedChunk, nextIndex);\n\n    //if (blockID == NONE || Blocks[blockID].waterBreak){ //calculate diffs\n    //    diffs[index] = (startBlockID - (_lowIndex - 1));\n    //    adjOwners[index] = owner;\n    //    adjIndices[index++] = nextIndex;\n    //} else if (IS_LIQUID(blockID)){ //tmp CANT FLOW THOUGH FULL WATER\n\n    //    if (nextCoord > 0){ //extra flow. its the secret!\n    //        adjAdjIndices[index] = nextIndex - CHUNK_WIDTH;\n    //        adjAdjOwners[index] = owner;\n    //    } else if (owner->back && owner->back->isAccessible){\n    //        adjAdjIndices[index] = nextIndex - CHUNK_WIDTH + CHUNK_LAYER;\n    //        adjAdjOwners[index] = owner->back;\n    //    }\n    //    diffs[index] = (startBlockID - blockID);\n    //    adjOwners[index] = owner;\n    //    adjIndices[index++] = nextIndex;\n    //}\n\n    ////Right Direction\n    //if (pos.x < CHUNK_WIDTH - 1) {\n    //    nextIndex = startBlockIndex + 1;\n    //    owner = _chunk;\n    //    nextCoord = pos.x + 1;\n    //} else if (_chunk->right && _chunk->right->isAccessible) {\n    //    nextIndex = startBlockIndex + 1 - CHUNK_WIDTH;\n    //    owner = _chunk->right;\n    //    nextCoord = 0;\n    //} else {\n    //    return;\n    //}\n\n    //blockID = owner->getBlockIDSafe(_lockedChunk, nextIndex);\n\n    //if (blockID == NONE || Blocks[blockID].waterBreak){ //calculate diffs\n    //    diffs[index] = (startBlockID - (_lowIndex - 1));\n    //    adjOwners[index] = owner;\n    //    adjIndices[index++] = nextIndex;\n    //} else if (IS_LIQUID(blockID)){ //tmp CANT FLOW THOUGH FULL WATER\n\n    //    if (nextCoord < CHUNK_WIDTH - 1){ //extra flow. its the secret!\n    //        adjAdjIndices[index] = nextIndex + 1;\n    //        adjAdjOwners[index] = owner;\n    //    } else if (owner->right && owner->right->isAccessible){\n    //        adjAdjIndices[index] = nextIndex + 1 - CHUNK_WIDTH;\n    //        adjAdjOwners[index] = owner->right;\n    //    }\n    //    diffs[index] = (startBlockID - blockID);\n    //    adjOwners[index] = owner;\n    //    adjIndices[index++] = nextIndex;\n    //}\n\n    ////Front Direction\n    //if (pos.z < CHUNK_WIDTH - 1) {\n    //    nextIndex = startBlockIndex + CHUNK_WIDTH;\n    //    owner = _chunk;\n    //    nextCoord = pos.z + 1;\n    //} else if (_chunk->front && _chunk->front->isAccessible) {\n    //    nextIndex = startBlockIndex + CHUNK_WIDTH - CHUNK_LAYER;\n    //    owner = _chunk->front;\n    //    nextCoord = 0;\n    //} else {\n    //    return;\n    //}\n\n    //blockID = owner->getBlockIDSafe(_lockedChunk, nextIndex);\n\n    //if (blockID == NONE || Blocks[blockID].waterBreak){ //calculate diffs\n    //    diffs[index] = (startBlockID - (_lowIndex - 1));\n    //    adjOwners[index] = owner;\n    //    adjIndices[index++] = nextIndex;\n    //} else if (IS_LIQUID(blockID)){ //tmp CANT FLOW THOUGH FULL WATER\n\n    //    if (nextCoord < CHUNK_WIDTH - 1){ //extra flow. its the secret!\n    //        adjAdjIndices[index] = nextIndex + CHUNK_WIDTH;\n    //        adjAdjOwners[index] = owner;\n    //    } else if (owner->front && owner->front->isAccessible){\n    //        adjAdjIndices[index] = nextIndex + CHUNK_WIDTH - CHUNK_LAYER;\n    //        adjAdjOwners[index] = owner->front;\n    //    }\n    //    diffs[index] = (startBlockID - blockID);\n    //    adjOwners[index] = owner;\n    //    adjIndices[index++] = nextIndex;\n    //}\n\n  \n\n    ////Spread the liquid\n    //int numAdj = index + 1;\n    //for (int i = 0; i < index; i++){\n    //    nextIndex = adjIndices[i];\n    //    owner = adjOwners[i];\n    //    diff = diffs[i] / numAdj;\n    //    //TODO(Ben): cache this instead\n    //    blockID = owner->getBlockIDSafe(_lockedChunk, nextIndex);\n\n    //    if (diff > 0){\n    //        //diff /= num;\n    //        if (diff < (startBlockID - _lowIndex + 1)){\n    //            if (blockID == NONE){\n    //                ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, _lowIndex - 1 + diff);\n    //            } else if (Blocks[blockID].waterBreak){\n    //                ChunkUpdater::removeBlock(m_chunkManager, m_physicsEngine, owner, _lockedChunk, nextIndex, true);\n    //                ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, _lowIndex - 1 + diff);\n    //            } else{\n    //                ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, blockID + diff);\n    //            }\n\n    //           \n    //            startBlockID -= diff;\n    //            if (diff > 10 && inFrustum) particleEngine.addParticles(m_chunkManager, 1, f64v3(position.x + pos.x, position.y + pos.y, position.z + pos.z), 0, 0.1, 16665, 1111, f32v4(255.0f, 255.0f, 255.0f, 255.0f), Blocks[blockID].particleTex, 0.5f, 8);\n    //           \n    //            if (owner != _chunk) {\n    //                owner->changeState(ChunkStates::WATERMESH);\n    //                ChunkUpdater::updateNeighborStates(owner, nextIndex, ChunkStates::WATERMESH);\n    //            }\n\n    //            hasChanged = 1;\n    //        }\n    //    }\n    //}\n    ////Extra movement for more realistic flow\n    //for (int i = 0; i < index; i++) {\n    //    if (adjAdjOwners[i]){\n    //        owner = adjAdjOwners[i];\n    //        nextIndex = adjAdjIndices[i];\n    //        blockID = owner->getBlockIDSafe(_lockedChunk, nextIndex);\n    //        if (blockID == NONE && startBlockID > _lowIndex){\n    //            diff = (startBlockID - _lowIndex + 1) / 2;\n    //            startBlockID -= diff;\n\n    //            ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, _lowIndex - 1 + diff);\n\n    //            if (owner != _chunk) {\n    //                owner->changeState(ChunkStates::WATERMESH);\n    //                ChunkUpdater::updateNeighborStates(owner, nextIndex, ChunkStates::WATERMESH);\n    //            }     \n    //            hasChanged = 1;\n    //        } else if (blockID >= _lowIndex && blockID < startBlockID - 1){\n    //            diff = (startBlockID - blockID) / 2;\n\n    //            ChunkUpdater::placeBlockFromLiquidPhysics(owner, _lockedChunk, nextIndex, blockID + diff);\n    //            startBlockID -= diff;\n    //     \n    //            if (owner != _chunk) {\n    //                owner->changeState(ChunkStates::WATERMESH);\n    //                ChunkUpdater::updateNeighborStates(owner, nextIndex, ChunkStates::WATERMESH);\n    //            }\n    //            hasChanged = 1;\n    //        }\n    //    }\n    //}\n\n    //if (hasChanged) {\n    //    ChunkUpdater::placeBlockFromLiquidPhysicsSafe(_chunk, _lockedChunk, startBlockIndex, startBlockID);\n\n    //    _chunk->changeState(ChunkStates::WATERMESH);\n    //    ChunkUpdater::updateNeighborStates(_chunk, pos, ChunkStates::WATERMESH);\n    //}\n}\n\nvoid CAEngine::powderPhysics(int blockIndex VORB_UNUSED)\n{\n    //// Directional constants\n    //#define LEFT 0\n    //#define RIGHT 1\n    //#define FRONT 2\n    //#define BACK 3\n    //// Every permutation of 0-3 for random axis directions\n    //#define DIRS_SIZE 96\n    //static const int DIRS[DIRS_SIZE] = { 0, 1, 2, 3, 0, 1, 3, 2, 0, 2, 3, 1, 0, 2, 1, 3, 0, 3, 2, 1, 0, 3, 1, 2,\n    //    1, 0, 2, 3, 1, 0, 3, 2, 1, 2, 0, 3, 1, 2, 3, 0, 1, 3, 2, 0, 1, 3, 0, 2,\n    //    2, 0, 1, 3, 2, 0, 3, 1, 2, 1, 3, 0, 2, 1, 0, 3, 2, 3, 0, 1, 2, 3, 1, 0,\n    //    3, 0, 1, 2, 3, 0, 2, 1, 3, 1, 2, 0, 3, 1, 0, 2, 3, 2, 0, 1, 3, 2, 1, 0 };\n\n    //int blockData = _chunk->getBlockDataSafe(_lockedChunk, blockIndex);\n    //int nextBlockData, nextBlockIndex;\n    //// Make sure this is a powder block\n    //if (GETBLOCK(blockData).caAlg != CA_ALGORITHM::POWDER) return;\n\n    //Chunk* nextChunk;\n    //i32v3 pos = getPosFromBlockIndex(blockIndex);\n\n    //// *** Falling in Y direction ***\n    //// Get bottom block\n    //nextBlockData = vvox::getBottomBlockData(_chunk, _lockedChunk, blockIndex, pos.y, nextBlockIndex, nextChunk);\n    //// Check for edge\n    //if (nextBlockData == -1) return;\n    //// Since getXXXBlockData may lock a chunk, we need this\n    //_lockedChunk = nextChunk;\n    //// Get block info\n    //const Block& bottomBlock = GETBLOCK(nextBlockData);\n    //// Check if we can move down\n    //if (bottomBlock.isCrushable) {\n    //    // Move down and crush block\n    //    ChunkUpdater::placeBlock(nextChunk, _lockedChunk, nextBlockIndex, blockData);\n    //    ChunkUpdater::removeBlockSafe(m_chunkManager, m_physicsEngine, _chunk, _lockedChunk, blockIndex, false);\n    //    return;\n    //} else if (bottomBlock.powderMove) {\n    //    // Move down and swap places\n    //    ChunkUpdater::placeBlock(nextChunk, _lockedChunk, nextBlockIndex, blockData);\n    //    ChunkUpdater::placeBlockSafe(_chunk, _lockedChunk, blockIndex, nextBlockData);\n    //    return;\n    //} else if (bottomBlock.caAlg != CA_ALGORITHM::POWDER) {\n    //    // We can only slide on powder, so if its not powder, we return.\n    //    return;\n    //}\n\n    //// We use _dirIndex to avoid any calls to rand(). We dont get truly random direction but\n    //// it appears random.\n    //#define NUM_AXIS 4\n    //_dirIndex += NUM_AXIS;\n    //// Wrap back to zero\n    //if (_dirIndex == DIRS_SIZE) _dirIndex = 0;\n    //// Loop through our 4 \"random\" directions\n    //for (int i = _dirIndex; i < _dirIndex + NUM_AXIS; i++) {\n    //    // Get the neighbor block in the direction\n    //    switch (DIRS[i]) {\n    //        case LEFT:\n    //            // Only lock the chunk if we know we aren't about to go to a neighbor\n    //            if (pos.x != 0) vvox::swapLockedChunk(_chunk, _lockedChunk);\n    //            nextBlockData = vvox::getLeftBlockData(_chunk, _lockedChunk, blockIndex, pos.x,\n    //                                                     nextBlockIndex, nextChunk);\n    //            break;\n    //        case RIGHT:\n    //            if (pos.x != CHUNK_WIDTH - 1) vvox::swapLockedChunk(_chunk, _lockedChunk);\n    //            nextBlockData = vvox::getRightBlockData(_chunk, _lockedChunk, blockIndex, pos.x,\n    //                                                      nextBlockIndex, nextChunk);\n    //            break;\n    //        case BACK:\n    //            if (pos.z != 0) vvox::swapLockedChunk(_chunk, _lockedChunk);\n    //            nextBlockData = vvox::getBackBlockData(_chunk, _lockedChunk, blockIndex, pos.z,\n    //                                                     nextBlockIndex, nextChunk);\n    //            break;\n    //        case FRONT:\n    //            if (pos.z != CHUNK_WIDTH - 1) vvox::swapLockedChunk(_chunk, _lockedChunk);\n    //            nextBlockData = vvox::getFrontBlockData(_chunk, _lockedChunk, blockIndex, pos.z,\n    //                                                      nextBlockIndex, nextChunk);\n    //            break;\n    //    }\n    //    // Check for edge\n    //    if (nextBlockData == -1) return;\n    //    // Since getXXXBlockData may lock a chunk, we need this\n    //    _lockedChunk = nextChunk;\n    //    // Check bottom\n    //    const Block& diagonalBlock = GETBLOCK(vvox::getBottomBlockData(nextChunk, _lockedChunk, \n    //                                          nextBlockIndex));\n    //    // We only move to the side if we can fall down the next update\n    //    if (diagonalBlock.powderMove || diagonalBlock.isCrushable) {\n    //        // Get block info\n    //        const Block& nextBlock = GETBLOCK(nextBlockData);\n    //        // Check if we can move\n    //        if (nextBlock.isCrushable) {\n    //            // Move and crush block\n    //            ChunkUpdater::placeBlockSafe(nextChunk, _lockedChunk, nextBlockIndex, blockData);\n    //            ChunkUpdater::removeBlockSafe(m_chunkManager, m_physicsEngine, _chunk, _lockedChunk, blockIndex, false);\n    //            return;\n    //        } else if (nextBlock.powderMove) {\n    //            // Move and swap places\n    //            ChunkUpdater::placeBlockSafe(nextChunk, _lockedChunk, nextBlockIndex, blockData);\n    //            ChunkUpdater::placeBlockSafe(_chunk, _lockedChunk, blockIndex, nextBlockData);\n    //            return;\n    //        }\n    //    }\n    //}\n}\n"
  },
  {
    "path": "SoA/CAEngine.h",
    "content": "#pragma once\n#include <Vorb/io/Keg.h>\n#include <Vorb/VorbPreDecl.inl>\n\n#include \"CellularAutomataTask.h\"\n#include \"Constants.h\"\n#include \"LiquidData.h\"\n\nDECL_VIO(class IOManager)\n\nclass ChunkManager;\nclass Chunk;\nclass PhysicsEngine;\n\n/// Resolution of CA updates in frames\n#define CA_TICK_RES 4\n/// Should be half of CA_TICK_RES\n#define HALF_CA_TICK_RES 2\n\nclass CaPhysicsData {\npublic:\n    ui32 liquidLevels = 0; ///< Number of block IDs reserved for liquid\n    ui32 updateRate = 0; ///< Update speed of the CA\n    CAAlgorithm alg; ///< CA algorithm to use\n};\nKEG_TYPE_DECL(CaPhysicsData);\n\ntypedef std::map<nString, CaPhysicsType*> CaPhysicsTypeDict;\ntypedef std::vector<CaPhysicsType*> CaPhysicsTypeList;\n\nclass CaPhysicsType {\npublic:\n\n    /// Updates the type.\n    /// @return true if it this physics type should simulate\n    bool update();\n\n    /// Loads the data from a yml file\n    /// @param filePath: path of the yml file\n    /// @param ioManager: IOManager that will read the file\n    /// @return true on success\n    bool loadFromYml(const nString& filePath, const vio::IOManager* ioManager);\n\n    // Getters\n    const int& getCaIndex() const { return _caIndex; }\n    const ui32& getUpdateRate() const { return _data.updateRate; }\n    const CAAlgorithm& getCaAlg() const { return _data.alg; }\n    const bool& getIsEven() const { return _isEven; }\n\n    // Static functions\n    /// Gets the number of CA types currently cached\n    static int getNumCaTypes() { return typesArray.size(); }\n    /// Clears all the cached types\n    static void clearTypes();\n\n    static CaPhysicsTypeList typesArray; ///< Stores cached types\n    static CaPhysicsTypeDict typesCache; ///< Stores cached types mapped to filepath\nprivate:\n\n    CaPhysicsData _data; ///< The algorithm specific data\n    int _caIndex; ///< index into typesArray\n    bool _isEven = false;  ///< Used for optimization, only update odd or even chunks at any time\n\n    ui32 _ticks = 0; ///< Counts the ticks\n};\n\nclass CAEngine {\npublic:\n    CAEngine(ChunkManager* chunkManager, PhysicsEngine* physicsEngine);\n    void setChunk(Chunk* chunk) { _chunk = chunk; }\n    void updateSpawnerBlocks(bool powders);\n    void updateLiquidBlocks(int caIndex);\n    void updatePowderBlocks(int caIndex);\nprivate:\n    \n    void liquidPhysics(i32 startBlockIndex, i32 b);\n    void powderPhysics(i32 c);\n\n//    i32 _dirIndex;\n    i32 _lowIndex;\n    i32 _range;\n    i32 _highIndex;\n    std::vector<ui16> _usedUpdateFlagList;\n    bool _blockUpdateFlagList[CHUNK_SIZE];\n    Chunk* _chunk;\n//    Chunk* _lockedChunk\n//    ChunkManager* m_chunkManager;\n//    PhysicsEngine* m_physicsEngine;\n};"
  },
  {
    "path": "SoA/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.1 FATAL_ERROR)\n\ncmake_policy(SET CMP0054 NEW)\n\nif (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)\n  if (APPLE)\n    message(\"\\nRun the build script:  build.sh\\n\")\n  endif (APPLE)\n  message(FATAL_ERROR \"You don't want to configure in the source folder!\")\nendif()\n\n\n#project(\"SoA\")\nlist(APPEND CMAKE_MODULE_PATH \"${CMAKE_SOURCE_DIR}/cmake\")\n\nenable_testing()\n\noption(TARGET_CXX_17 OFF)\n\nif(TARGET_CXX_17)\n    set(CMAKE_CXX_STANDARD 17)\nelse()\n    set(CMAKE_CXX_STANDARD 14)\nendif()\n\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nif (\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"GNU\" OR\n    \"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"Clang\")\n    option(USING_GDB \"Are we using gdb to debug?\" On)\n    option(EXTRA_DEBUG \"Should we add extra debug symbols?\" On)\n    # We could move OPTIMISE_ON_DEBUG outside and support MSVC no doubt.\n    option(OPTIMISE_ON_DEBUG \"Should we optimise a debug target?\" On)\n\n    set(warnings \"-Wall -Wextra -Wno-unknown-pragmas -Wno-strict-aliasing\")\n    if (\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"GNU\")\n        # This warning only exists for GCC.\n        set(warnings \"${warnings} -Wno-class-memaccess\")\n    endif()\n    ADD_DEFINITIONS(\n#        -std=c++11\n#        -std=c++0x\n        # Other flags\n        ${warnings}\n    )\n    \n    set(CMAKE_CXX_FLAGS_RELEASE \"-O3\")\n    if (${USING_GDB})\n        if (${EXTRA_DEBUG})\n            set(CMAKE_CXX_FLAGS_DEBUG \"-ggdb3\")\n        else()\n            set(CMAKE_CXX_FLAGS_DEBUG \"-ggdb\")\n        endif()\n    else()\n        if (${EXTRA_DEBUG})\n            set(CMAKE_CXX_FLAGS_DEBUG \"-g3\")\n        else()\n            set(CMAKE_CXX_FLAGS_DEBUG \"-g\")\n        endif()\n    endif ()\n    if (${OPTIMISE_ON_DEBUG})\n        # This is supported by both Clang and GCC as long as we are up-to-date.\n        # Should be fine going back as far as Ubuntu 17.10, and deffo fine on Arch.\n        set(CMAKE_CXX_FLAGS_DEBUG \"${CMAKE_CXX_FLAGS_DEBUG} -Og\")\n    endif()\nelseif (\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"MSVC\")\n    set(warnings \"/W4 /WX /EHsc\")\nendif()\n\nIF(APPLE)\n   INCLUDE_DIRECTORIES ( /System/Library/Frameworks )\n   FIND_LIBRARY(COCOA_LIBRARY Cocoa)\n   FIND_LIBRARY(GLUT_LIBRARY GLUT )\n   FIND_LIBRARY(OpenGL_LIBRARY OpenGL )\n   MARK_AS_ADVANCED (COCOA_LIBRARY\n                     GLUT_LIBRARY\n                     OpenGL_LIBRARY)\n   SET(EXTRA_LIBS ${COCOA_LIBRARY} ${GLUT_LIBRARY} ${OpenGL_LIBRARY})\nENDIF (APPLE)\n\n# Open GL\nfind_package(OpenGL)\nif (OPENGL_FOUND)\n   include_directories(SYSTEM ${OPENGL_INCLUDE_DIRS})\nendif (OPENGL_FOUND)\n\n## SDL\n#find_package(SDL)\n#if (SDL_FOUND)\n#   include_directories(SYSTEM ${SDL_INCLUDE_DIRS})\n#endif (SDL_FOUND)\n#\n## Glew\n#find_package(GLEW)\n#if (GLEW_FOUND)\n#   include_directories(SYSTEM ${GLEW_INCLUDE_DIRS})\n#endif (GLEW_FOUND)\n#\n## BOOST filesystem\n#set(Boost_USE_STATIC_LIBS OFF)\n#set(Boost_USE_MULTITHREADED ON)\n#set(Boost_USE_STATIC_RUNTIME OFF)\n#set(BOOST_VERSION 1.55.0)\n#set(BOOST_COMPONENTS filesystem)\n#find_package(Boost ${BOOST_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED)\n#if (Boost_FOUND)\n#   include_directories(SYSTEM ${BOOST_INCLUDE_DIRS})\n#endif (Boost_FOUND)\n\nhunter_add_package(glew)\nfind_package(glew CONFIG REQUIRED)\n#hunter_add_package(Boost COMPONENTS filesystem system)\n#find_package(Boost REQUIRED COMPONENTS filesystem system)\nhunter_add_package(SDL2)\nfind_package(SDL2 CONFIG REQUIRED)\nhunter_add_package(minizip)\nfind_package(minizip CONFIG REQUIRED)\nhunter_add_package(CreateLaunchers)\nfind_package(CreateLaunchers CONFIG REQUIRED)\n\ninclude_directories(${CMAKE_CURRENT_SOURCE_DIR})\ninclude_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/../deps/include)\n\n#lodepng\ninclude_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/../deps/lodepng)\n\n# readerwriterqueue\ninclude_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/../deps/readerwriterqueue)\n\n#set(extra_sources\n#    ${CMAKE_CURRENT_SOURCE_DIR}/../deps/lodepng/lodepng.cpp\n#    )\n\n#file(GLOB engine_files\n#    \"*.h\"\n#    \"*.cpp\"\n#\n\nset(SoA_headers\n    AABBCollidableComponentUpdater.h\n    AmbienceLibrary.h\n    AmbiencePlayer.h\n    AmbienceStream.h\n    Animation.h\n    App.h\n    ARProcessor.h\n    AtmosphereComponentRenderer.h\n    atomicops.h\n    AxisRotationComponentUpdater.h\n    Biome.h\n    BlendState.h\n    BlockData.h\n    BlockLoader.h\n    BlockPack.h\n    BlockTexture.h\n    BlockTextureAtlas.h\n    BlockTextureLoader.h\n    BlockTextureMethods.h\n    BlockTexturePack.h\n    BloomRenderStage.h\n    CAEngine.h\n    Camera.h\n    CellularAutomataTask.h\n    Chunk.h\n    ChunkAccessor.h\n    ChunkAllocator.h\n    ChunkGenerator.h\n    ChunkGrid.h\n    ChunkGridRenderStage.h\n    ChunkHandle.h\n    ChunkID.h\n    ChunkIOManager.h\n    ChunkMesh.h\n    ChunkMesher.h\n    ChunkMeshManager.h\n    ChunkMeshTask.h\n    ChunkQuery.h\n    ChunkRenderer.h\n    ChunkSphereComponentUpdater.h\n    ChunkUpdater.h\n    ClientState.h\n    CloudsComponentRenderer.h\n    Collision.h\n    CollisionComponentUpdater.h\n    ColoredFullQuadRenderer.h\n    ColorFilterRenderStage.h\n    CommonState.h\n    Computer.h\n    ConsoleFuncs.h\n    ConsoleMain.h\n    ConsoleTests.h\n    Constants.h\n    CutoutVoxelRenderStage.h\n    DebugRenderer.h\n    Density.h\n    DevConsole.h\n    DevConsoleView.h\n    DevHudRenderStage.h\n    DevScreen.h\n    DLLAPI.h\n    DLLLoader.h\n    DualContouringMesher.h\n    ECSTemplates.h\n    Errors.h\n    ExposureCalcRenderStage.h\n    FarTerrainComponentRenderer.h\n    FarTerrainComponentUpdater.h\n    FarTerrainPatch.h\n    Flora.h\n    FloraGenerator.h\n    FragFile.h\n    FreeMoveComponentUpdater.h\n    Frustum.h\n    FrustumComponentUpdater.h\n    GameManager.h\n    GameplayLoadScreen.h\n    GameplayRenderer.h\n    GamePlayScreen.h\n    GameRenderParams.h\n    GameSystem.h\n    GameSystemAssemblages.h\n    GameSystemComponentBuilders.h\n    GameSystemComponents.h\n    GameSystemUpdater.h\n    GasGiantComponentRenderer.h\n    GenerateTask.h\n    GeometrySorter.h\n    HdrRenderStage.h\n    HeadComponentUpdater.h\n    ImageAssetLoader.h\n    IniParser.h\n    InitScreen.h\n    InputMapper.h\n    Inputs.h\n    IRenderStage.h\n    Item.h\n    LenseFlareRenderer.h\n    LiquidData.h\n    LiquidVoxelRenderStage.h\n    LoadBar.h\n    LoadContext.h\n    LoadMonitor.h\n    LoadTaskBlockData.h\n    LoadTaskGameManager.h\n    LoadTaskStarSystem.h\n    LoadTaskTextures.h\n    MainMenuLoadScreen.h\n    MainMenuRenderer.h\n    MainMenuScreen.h\n    MainMenuScriptedUI.h\n    MainMenuSystemViewer.h\n    MarchingCubesTable.h\n    MaterialAtlas.h\n    MaterialData.h\n    MaterialStack.h\n    MetaSection.h\n    ModelMesher.h\n    ModInformation.h\n    ModPathResolver.h\n    MTRenderState.h\n    MTRenderStateManager.h\n    MusicPlayer.h\n    NightVisionRenderStage.h\n    Noise.h\n    Octree.h\n    OpaqueVoxelRenderStage.h\n    OptionsController.h\n    OrbitComponentRenderer.h\n    OrbitComponentUpdater.h\n    ParkourComponentUpdater.h\n    ParticleMesh.h\n    PauseMenu.h\n    PauseMenuRenderStage.h\n    PDA.h\n    PdaRenderStage.h\n    PhysicsBlockRenderStage.h\n    PhysicsComponentUpdater.h\n#    Planet.h\n    PlanetGenData.h\n    PlanetGenerator.h\n    PlanetGenLoader.h\n    PlanetHeightData.h\n#    PlanetRenderStage.h\n    PlanetRingsComponentRenderer.h\n    Positional.h\n    ProceduralChunkGenerator.h\n    ProgramGenDelegate.h\n    qef.h\n    readerwriterqueue.h\n    RegionFileManager.h\n    RenderUtils.h\n    ShaderAssetLoader.h\n    ShaderLoader.h\n    SkyboxRenderer.h\n    SkyboxRenderStage.h\n    SoaController.h\n    SoaEngine.h\n    SoaFileSystem.h\n    SoaOptions.h\n    SoAState.h\n    soaUtils.h\n    SonarRenderStage.h\n    SpaceSystem.h\n    SpaceSystemAssemblages.h\n    SpaceSystemComponentBuilders.h\n    SpaceSystemComponents.h\n    SpaceSystemComponentTables.h\n    SpaceSystemLoader.h\n    SpaceSystemLoadStructs.h\n    SpaceSystemRenderStage.h\n    SpaceSystemUpdater.h\n    SphericalHeightmapGenerator.h\n    SphericalTerrainComponentRenderer.h\n    SphericalTerrainComponentUpdater.h\n    SphericalVoxelComponentUpdater.h\n    SsaoRenderStage.h\n    StarComponentRenderer.h\n    Startup.h\n    stdafx.h\n    svd.h\n    SystemARRenderer.h\n    SystemBodyLoader.h\n    TerrainGenTextures.h\n    TerrainPatch.h\n    TerrainPatchConstants.h\n    TerrainPatchMesh.h\n    TerrainPatchMesher.h\n    TerrainPatchMeshManager.h\n    TerrainPatchMeshTask.h\n    TestBiomeScreen.h\n    TestBlockViewScreen.h\n    TestConnectedTextureScreen.h\n    TestConsoleScreen.h\n    TestDeferredScreen.h\n    TestDisplacementMappingScreen.h\n    TestGasGiantScreen.h\n    TestMappingScreen.h\n    TestNewBlockAPIScreen.h\n    TestNoiseScreen.h\n    TestPlanetGenScreen.h\n    TestScriptScreen.h\n    TestStarScreen.h\n    TestUIScreen.h\n    TestVoxelModelScreen.h\n    textureUtils.h\n    Thread.h\n    TransparentVoxelRenderStage.h\n    Vertex.h\n    VoxelBits.h\n    VoxelCoordinateSpaces.h\n    VoxelEditor.h\n    VoxelLightEngine.h\n    VoxelMatrix.h\n    VoxelMesh.h\n    VoxelMesher.h\n    VoxelModel.h\n    VoxelModelLoader.h\n    VoxelModelMesh.h\n    VoxelModelRenderer.h\n    VoxelNodeSetter.h\n    VoxelNodeSetterTask.h\n    VoxelRay.h\n    VoxelSpaceConversions.h\n    VoxelSpaceUtils.h\n    VoxelUpdateBufferer.h\n    VoxelUtils.h\n    VoxelVertices.h\n    VoxPool.h\n    VRayHelper.h\n#    WorldIO.h\n    WorldStructs.h\n    WSO.h\n    WSOAtlas.h\n    WSOData.h\n    WSOScanner.h\n    ZipFile.h\n)\n\nset(SoA_inline\n)\n\nset(SoA_sources\n    AABBCollidableComponentUpdater.cpp\n    AmbienceLibrary.cpp\n    AmbiencePlayer.cpp\n    AmbienceStream.cpp\n    App.cpp\n    ARProcessor.cpp\n    AtmosphereComponentRenderer.cpp\n    AxisRotationComponentUpdater.cpp\n    Biome.cpp\n    BlockData.cpp\n    BlockLoader.cpp\n    BlockPack.cpp\n    BlockTexture.cpp\n    BlockTextureLoader.cpp\n    BlockTextureMethods.cpp\n    BlockTexturePack.cpp\n    BloomRenderStage.cpp\n    CAEngine.cpp\n    Camera.cpp\n    CellularAutomataTask.cpp\n    Chunk.cpp\n    ChunkAccessor.cpp\n    ChunkAllocator.cpp\n    ChunkGenerator.cpp\n    ChunkGrid.cpp\n    ChunkGridRenderStage.cpp\n    ChunkIOManager.cpp\n    ChunkMesh.cpp\n    ChunkMesher.cpp\n    ChunkMeshManager.cpp\n    ChunkMeshTask.cpp\n    ChunkQuery.cpp\n    ChunkRenderer.cpp\n    ChunkSphereComponentUpdater.cpp\n    ChunkUpdater.cpp\n#    CloseTerrainPatch.cpp\n    CloudsComponentRenderer.cpp\n    Collision.cpp\n    CollisionComponentUpdater.cpp\n    ColoredFullQuadRenderer.cpp\n    ColorFilterRenderStage.cpp\n    Computer.cpp\n    ConsoleTests.cpp\n    CutoutVoxelRenderStage.cpp\n    DebugRenderer.cpp\n    Density.cpp\n    DevConsole.cpp\n    DevConsoleView.cpp\n    DevHudRenderStage.cpp\n    DevScreen.cpp\n    DualContouringMesher.cpp\n    ECSTemplates.cpp\n    Errors.cpp\n    ExposureCalcRenderStage.cpp\n    FarTerrainComponentRenderer.cpp\n    FarTerrainComponentUpdater.cpp\n    FarTerrainPatch.cpp\n    Flora.cpp\n    FloraGenerator.cpp\n    FragFile.cpp\n    FreeMoveComponentUpdater.cpp\n    Frustum.cpp\n    FrustumComponentUpdater.cpp\n    GameManager.cpp\n    GameplayLoadScreen.cpp\n    GameplayRenderer.cpp\n    GamePlayScreen.cpp\n    GameRenderParams.cpp\n    GameSystem.cpp\n    GameSystemAssemblages.cpp\n    GameSystemComponentBuilders.cpp\n    GameSystemComponents.cpp\n    GameSystemUpdater.cpp\n    GasGiantComponentRenderer.cpp\n    GenerateTask.cpp\n    GeometrySorter.cpp\n    HdrRenderStage.cpp\n    HeadComponentUpdater.cpp\n    ImageAssetLoader.cpp\n    IniParser.cpp\n    InitScreen.cpp\n    InputMapper.cpp\n    Inputs.cpp\n    Item.cpp\n    LenseFlareRenderer.cpp\n    LiquidVoxelRenderStage.cpp\n    LoadBar.cpp\n    LoadMonitor.cpp\n    main.cpp\n    MainMenuLoadScreen.cpp\n    MainMenuRenderer.cpp\n    MainMenuScreen.cpp\n    MainMenuScriptedUI.cpp\n    MainMenuSystemViewer.cpp\n    MetaSection.cpp\n    ModelMesher.cpp\n    ModPathResolver.cpp\n    MTRenderStateManager.cpp\n    MusicPlayer.cpp\n    NightVisionRenderStage.cpp\n    Noise.cpp\n    Octree.cpp\n    OpaqueVoxelRenderStage.cpp\n    OptionsController.cpp\n    OrbitComponentRenderer.cpp\n    OrbitComponentUpdater.cpp\n    ParkourComponentUpdater.cpp\n    PauseMenu.cpp\n    PauseMenuRenderStage.cpp\n    PDA.cpp\n    PdaRenderStage.cpp\n    PhysicsBlockRenderStage.cpp\n    PhysicsComponentUpdater.cpp\n#    Planet.cpp\n    PlanetGenData.cpp\n    PlanetGenerator.cpp\n    PlanetGenLoader.cpp\n#    PlanetRenderStage.cpp\n    PlanetRingsComponentRenderer.cpp\n    ProceduralChunkGenerator.cpp\n    qef.cpp\n    RegionFileManager.cpp\n    ShaderAssetLoader.cpp\n    ShaderLoader.cpp\n    SkyboxRenderer.cpp\n    SkyboxRenderStage.cpp\n    SoaController.cpp\n    SoaEngine.cpp\n    SoaFileSystem.cpp\n    SoaOptions.cpp\n    SoaState.cpp\n    SonarRenderStage.cpp\n    SpaceSystem.cpp\n    SpaceSystemAssemblages.cpp\n    SpaceSystemComponentBuilders.cpp\n    SpaceSystemComponentTables.cpp\n    SpaceSystemLoader.cpp\n    SpaceSystemLoadStructs.cpp\n    SpaceSystemRenderStage.cpp\n    SpaceSystemUpdater.cpp\n    SphericalHeightmapGenerator.cpp\n    SphericalTerrainComponentRenderer.cpp\n    SphericalTerrainComponentUpdater.cpp\n    SphericalVoxelComponentUpdater.cpp\n    SsaoRenderStage.cpp\n    StarComponentRenderer.cpp\n    Startup.cpp\n    stdafx.cpp\n    svd.cpp\n    SystemARRenderer.cpp\n    SystemBodyLoader.cpp\n    TerrainGenTextures.cpp\n    TerrainPatch.cpp\n    TerrainPatchMesh.cpp\n    TerrainPatchMesher.cpp\n    TerrainPatchMeshManager.cpp\n    TerrainPatchMeshTask.cpp\n    TestBiomeScreen.cpp\n    TestBlockViewScreen.cpp\n    TestConnectedTextureScreen.cpp\n    TestConsoleScreen.cpp\n    TestDeferredScreen.cpp\n    TestDisplacementMappingScreen.cpp\n    TestGasGiantScreen.cpp\n    TestMappingScreen.cpp\n    TestNewBlockAPIScreen.cpp\n    TestNoiseScreen.cpp\n    TestPlanetGenScreen.cpp\n    TestScriptScreen.cpp\n    TestStarScreen.cpp\n    TestUIScreen.cpp\n    TestVoxelModelScreen.cpp\n    TransparentVoxelRenderStage.cpp\n    VoxelEditor.cpp\n    VoxelLightEngine.cpp\n    VoxelMatrix.cpp\n    VoxelMesher.cpp\n    VoxelModel.cpp\n    VoxelModelLoader.cpp\n    VoxelModelMesh.cpp\n    VoxelModelRenderer.cpp\n    VoxelNodeSetter.cpp\n    VoxelNodeSetterTask.cpp\n    VoxelRay.cpp\n    VoxelSpaceConversions.cpp\n    VoxelSpaceUtils.cpp\n    VoxPool.cpp\n    VRayHelper.cpp\n#    WorldIO.cpp\n    WorldStructs.cpp\n    WSO.cpp\n    WSOAtlas.cpp\n    WSOScanner.cpp\n    ZipFile.cpp\n)\n\nset(skip_these_for_now\n)\n\n#foreach(eng_file in ${skip_these_for_now})\n#  list(REMOVE_ITEM engine_files ${CMAKE_CURRENT_SOURCE_DIR}/${eng_file})\n#endforeach()\n\n# doxygen\nfind_package(Doxygen)\noption(BUILD_DOCUMENTATION \"Create and install the HTML based API documentation (requires Doxygen)\" ${DOXYGEN_FOUND})\n\nif(BUILD_DOCUMENTATION)\n    if(NOT DOXYGEN_FOUND)\n        message(FATAL_ERROR \"Doxygen is needed to build the documentation.\")\n    endif()\n\n    set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)\n    set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)\n\n    configure_file(${doxyfile_in} ${doxyfile} @ONLY)\n\n    add_custom_target(doc\n        COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}\n        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n        COMMENT \"Generating API documentation with Doxygen\"\n        VERBATIM)\n\n    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc)\nendif()\n\nadd_executable(soa \n    ${SoA_headers}\n    ${SoA_inline}\n    ${SoA_sources}\n#    ${extra_sources}\n)\n\ntarget_link_libraries(soa\n#    ${OPENGL_INCLUDE_DIRS}\n    OpenGL::GL\n    SDL2::SDL2main\n    SDL2::SDL2\n    glew::glew\n#    Boost::filesystem\n#    Boost::system\n    vorb\n    minizip::minizip\n#    ${SDL_INCLUDE_DIRS}\n#    ${GLEW_INCLUDE_DIRS}\n#    ${BOOST_INCLUDE_DIRS}\n)\n\ninclude(CreateLaunchers)\n\ncreate_target_launcher(soa\n    ARGS \"-a\"\n\tRUNTIME_LIBRARY_DIRS \"${CMAKE_BINARY_DIR}\"\n\tWORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}/../game\"\n)\n"
  },
  {
    "path": "SoA/Camera.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Camera.h\"\n\n#include <SDL2/SDL.h>\n#include <Vorb/utils.h>\n\n#include \"SoaOptions.h\"\n\n#include <glm/glm.hpp>\n#include <glm/gtc/matrix_transform.hpp>\n\nconst f32v3 Camera::UP_ABSOLUTE = f32v3(0.0f, 1.0f, 0.0f);\n\nCamera::Camera() {\n    // Empty\n}\n\nvoid Camera::init(float aspectRatio) {\n    m_aspectRatio = aspectRatio;\n}\n\nvoid Camera::offsetPosition(const f64v3& offset) {\n    m_position += offset;\n    m_viewChanged = true;\n}\n\nvoid Camera::offsetPosition(const f32v3& offset) {\n    m_position += offset;\n    m_viewChanged = true;\n}\n\nvoid Camera::update() {\n    f32 optFov = soaOptions.get(OPT_FOV).value.f;\n    if (m_fieldOfView != optFov) {\n        setFieldOfView(optFov);\n    }\n\n    bool updateFrustum = false;\n    if (m_viewChanged) {\n        updateView();\n        m_viewChanged = false;\n        updateFrustum = true;\n    }\n    if (m_projectionChanged) {\n        updateProjection();\n        m_projectionChanged = false;\n        updateFrustum = true;\n    }\n\n    if (updateFrustum) {\n        m_viewProjectionMatrix = m_projectionMatrix * m_viewMatrix;\n        m_frustum.updateFromWVP(m_viewProjectionMatrix);\n    }\n}\n\nvoid Camera::updateView() {\n    m_viewMatrix = glm::lookAt(f32v3(0.0f), m_direction, m_up);\n}\n\nvoid Camera::updateProjection() {\n    m_frustum.setCamInternals(m_fieldOfView, m_aspectRatio, m_zNear, m_zFar);\n    m_projectionMatrix = glm::perspective(m_fieldOfView, m_aspectRatio, m_zNear, m_zFar);\n}\n\nvoid Camera::applyRotation(const f32q& rot) {\n    m_direction = rot * m_direction;\n    m_right = rot * m_right;\n    m_up = glm::normalize(glm::cross(m_right, m_direction));\n\n    m_viewChanged = true;\n}\n\nvoid Camera::rotateFromMouseAbsoluteUp(float dx, float dy, float speed, bool clampVerticalRotation /* = false*/) {\n    f32q upQuat = glm::angleAxis(dy * speed, m_right);\n    f32q rightQuat = glm::angleAxis(dx * speed, UP_ABSOLUTE);\n\n    f32v3 previousDirection = m_direction;\n    f32v3 previousUp = m_up;\n    f32v3 previousRight = m_right;\n\n    applyRotation(upQuat * rightQuat);\n\n    if (clampVerticalRotation && m_up.y < 0) {\n        m_direction = previousDirection;\n        m_up = previousUp;\n        m_right = previousRight;\n        rotateFromMouseAbsoluteUp(dx, 0.0f, speed);\n    }\n}\n\nvoid Camera::rotateFromMouse(float dx, float dy, float speed) {\n    f32q upQuat = glm::angleAxis(dy * speed, m_right);\n    f32q rightQuat = glm::angleAxis(dx * speed, m_up);\n \n    applyRotation(upQuat * rightQuat);\n}\n\nvoid Camera::rollFromMouse(float dx, float speed) {\n    f32q frontQuat = glm::angleAxis(dx * speed, m_direction);\n\n    applyRotation(frontQuat);\n}\n\nvoid Camera::setOrientation(const f64q& orientation) {\n    m_direction = orientation * f64v3(0.0, 0.0, 1.0);\n    m_right = orientation * f64v3(1.0, 0.0, 0.0);\n    m_up = orientation * f64v3(0.0, 1.0, 0.0);\n    m_viewChanged = true;\n}\n\nf32v3 Camera::worldToScreenPoint(const f32v3& worldPoint) const {\n    // Transform world to clipping coordinates\n    f32v4 clipPoint = m_viewProjectionMatrix * f32v4(worldPoint, 1.0f);\n    clipPoint.x /= clipPoint.w;\n    clipPoint.y /= clipPoint.w;\n    clipPoint.z /= clipPoint.w;\n    return f32v3((clipPoint.x + 1.0) / 2.0f,\n                 (1.0 - clipPoint.y) / 2.0f,\n                 clipPoint.z);\n}\n\nf32v3 Camera::worldToScreenPointLogZ(const f32v3& worldPoint, f32 zFar) const {\n    // Transform world to clipping coordinates\n    f32v4 clipPoint = m_viewProjectionMatrix * f32v4(worldPoint, 1.0f);\n    clipPoint.z = log2(glm::max(0.0001f, clipPoint.w + 1.0f)) * 2.0f / log2(zFar + 1.0f) - 1.0f;\n    clipPoint.x /= clipPoint.w;\n    clipPoint.y /= clipPoint.w;\n    return f32v3((clipPoint.x + 1.0f) / 2.0f,\n                 (1.0f - clipPoint.y) / 2.0f,\n                 clipPoint.z);\n}\n\nf32v3 Camera::worldToScreenPoint(const f64v3& worldPoint) const {\n    // Transform world to clipping coordinates\n    f64v4 clipPoint = f64m4(m_viewProjectionMatrix) * f64v4(worldPoint, 1.0);\n    clipPoint.x /= clipPoint.w;\n    clipPoint.y /= clipPoint.w;\n    clipPoint.z /= clipPoint.w;\n    return f32v3((clipPoint.x + 1.0f) / 2.0f,\n                 (1.0f - clipPoint.y) / 2.0f,\n                 clipPoint.z);\n}\n\nf32v3 Camera::worldToScreenPointLogZ(const f64v3& worldPoint, f64 zFar) const {\n    // Transform world to clipping coordinates\n    f64v4 clipPoint = f64m4(m_viewProjectionMatrix) * f64v4(worldPoint, 1.0);\n    clipPoint.z = log2(glm::max(0.0001, clipPoint.w + 1.0)) * 2.0 / log2(zFar + 1.0) - 1.0;\n    clipPoint.x /= clipPoint.w;\n    clipPoint.y /= clipPoint.w;\n    return f32v3((clipPoint.x + 1.0) / 2.0,\n                 (1.0 - clipPoint.y) / 2.0,\n                 clipPoint.z);\n}\n\nf32v3 Camera::getPickRay(const f32v2& ndcScreenPos) const {\n    f32v4 clipRay(ndcScreenPos.x, ndcScreenPos.y, - 1.0f, 1.0f);\n    f32v4 eyeRay = glm::inverse(m_projectionMatrix) * clipRay;\n    eyeRay = f32v4(eyeRay.x, eyeRay.y, -1.0f, 0.0f);\n    return glm::normalize(f32v3(glm::inverse(m_viewMatrix) * eyeRay));\n}\n\nvoid CinematicCamera::update()\n{\n    m_viewChanged = true;\n    /// Smooth movement towards target\n\n    if (m_isDynamic) {\n        if (ABS(m_focalLength - m_targetFocalLength) < 0.1) {\n            m_focalLength = m_targetFocalLength;\n        } else {\n            m_focalLength = lerp(m_focalLength, m_targetFocalLength, m_speed);\n        }\n        m_focalPoint = lerp(m_focalPoint, m_targetFocalPoint, m_speed);\n        m_direction = lerp(m_direction, m_targetDirection, (f32)m_speed);\n        m_right = lerp(m_right, m_targetRight, (f32)m_speed);\n\n        m_position = m_focalPoint - f64v3(m_direction) * m_focalLength;\n    }\n\n    // Call base class update\n    Camera::update();\n}\n\n\nvoid CinematicCamera::applyRotation(const f32q& rot) {\n    m_targetDirection = rot * m_targetDirection;\n    m_targetRight = rot * m_targetRight;\n   \n    m_viewChanged = true;\n}\n\nvoid CinematicCamera::rotateFromMouse(float dx, float dy, float speed) {\n    f32q upQuat = glm::angleAxis(dy * speed, m_targetRight);\n    f32v3 targetUp = glm::normalize(glm::cross(m_targetRight, m_targetDirection));\n    f32q rightQuat = glm::angleAxis(dx * speed, targetUp);\n\n    applyRotation(upQuat * rightQuat);\n}\n\nvoid CinematicCamera::rollFromMouse(float dx, float speed) {\n    f32q frontQuat = glm::angleAxis(dx * speed, m_targetDirection);\n\n    applyRotation(frontQuat);\n}\n\nvoid CinematicCamera::offsetTargetFocalLength(float offset) {\n    m_targetFocalLength += offset;\n    if (m_targetFocalLength < 0.0) {\n        m_targetFocalLength = 0.0;\n    } else if (m_targetFocalLength > m_maxFocalLength) {\n        m_targetFocalLength = m_maxFocalLength;\n    }\n}\n\nvoid CinematicCamera::setTarget(const f64v3& targetFocalPoint, const f32v3& targetDirection,\n                                const f32v3& targetRight, double targetFocalLength) {\n    m_targetFocalPoint = targetFocalPoint;\n    m_targetDirection = targetDirection;\n    m_targetRight = targetRight;\n    m_targetFocalLength = targetFocalLength;\n}\n"
  },
  {
    "path": "SoA/Camera.h",
    "content": "#pragma once\n#include \"Frustum.h\"\n\nclass Camera\n{\npublic:\n    Camera();\n    void init(float aspectRatio);\n    void offsetPosition(const f64v3& offset);\n    void offsetPosition(const f32v3& offset);\n    void update();\n    void updateProjection();\n    virtual void applyRotation(const f32q& rot);\n    virtual void rotateFromMouseAbsoluteUp(float dx, float dy, float speed, bool clampVerticalRotation = false);\n    virtual void rotateFromMouse(float dx, float dy, float speed);\n    virtual void rollFromMouse(float dx, float speed);\n\n    // Frustum wrappers\n    bool pointInFrustum(const f32v3& pos) const { return m_frustum.pointInFrustum(pos); }\n    bool sphereInFrustum(const f32v3& pos, float radius) const { return m_frustum.sphereInFrustum(pos, radius); }\n\n    //setters\n    void setOrientation(const f64q& orientation);\n    void setFocalPoint(const f64v3& focalPoint) { m_focalPoint = focalPoint; m_viewChanged = 1; }\n    void setPosition(const f64v3& position) { m_focalPoint = position; m_position = position; m_focalLength = 0;  m_viewChanged = 1; }\n    void setDirection(const f32v3& direction) { m_direction = direction; m_viewChanged = 1; }\n    void setRight(const f32v3& right) { m_right = right; m_viewChanged = 1; }\n    void setUp(const f32v3& up) { m_up = up; m_viewChanged = 1; }\n    void setClippingPlane(float zNear, float zFar){ m_zNear = zNear; m_zFar = zFar; m_projectionChanged = 1; }\n    void setFieldOfView(float fieldOfView){ m_fieldOfView = fieldOfView; m_projectionChanged = 1; }\n    void setFocalLength(float focalLength) { m_focalLength = focalLength; m_viewChanged = 1; }\n    void setAspectRatio(float aspectRatio) { m_aspectRatio = aspectRatio; m_projectionChanged = 1; }\n\n    // Gets the position of a 3D point on the screen plane\n    f32v3 worldToScreenPoint(const f32v3& worldPoint) const;\n    f32v3 worldToScreenPointLogZ(const f32v3& worldPoint, f32 zFar) const;\n    f32v3 worldToScreenPoint(const f64v3& worldPoint) const;\n    f32v3 worldToScreenPointLogZ(const f64v3& worldPoint, f64 zFar) const;\n    f32v3 getPickRay(const f32v2& ndcScreenPos) const;\n\n    //getters\n    const f64v3& getPosition() const { return m_position; }\n    const f32v3& getDirection() const { return m_direction; }\n    const f32v3& getRight() const { return m_right; }\n    const f32v3& getUp() const { return m_up; }\n\n    const f32m4& getProjectionMatrix() const { return m_projectionMatrix; }\n    const f32m4& getViewMatrix() const { return m_viewMatrix; }\n    const f32m4& getViewProjectionMatrix() const { return m_viewProjectionMatrix; }\n\n    const f32& getNearClip() const { return m_zNear; }\n    const f32& getFarClip() const { return m_zFar; }\n    const f32& getFieldOfView() const { return m_fieldOfView; }\n    const f32& getAspectRatio() const { return m_aspectRatio; }\n    const f64& getFocalLength() const { return m_focalLength; }\n\n    const Frustum& getFrustum() const { return m_frustum; }\n\nprotected:\n    void normalizeAngles();\n    void updateView();\n\n    f32 m_zNear = 0.1f;\n    f32 m_zFar = 100000.0f;\n    f32 m_fieldOfView = 75.0f;\n    f32 m_aspectRatio = 4.0f / 3.0f;\n    f64 m_focalLength = 0.0;\n    f64 m_maxFocalLength = 10000000000000000000000.0;\n    bool m_viewChanged = true;\n    bool m_projectionChanged = true;\n\n    f64v3 m_focalPoint = f64v3(0.0);\n    f64v3 m_position = f64v3(0.0);\n    f32v3 m_direction = f32v3(1.0f, 0.0f, 0.0f);\n    f32v3 m_right = f32v3(0.0f, 0.0f, 1.0f);\n    f32v3 m_up = f32v3(0.0f, 1.0f, 0.0f);\n    static const f32v3 UP_ABSOLUTE;\n\n    f32m4 m_projectionMatrix;\n    f32m4 m_viewMatrix;\n    f32m4 m_viewProjectionMatrix;\n\n    Frustum m_frustum; ///< For frustum culling\n};\n\nclass CinematicCamera : public Camera\n{\npublic:\n    void update();\n\n    virtual void applyRotation(const f32q& rot) override;\n    virtual void rotateFromMouse(float dx, float dy, float speed) override;\n    virtual void rollFromMouse(float dx, float speed) override;\n\n    void offsetTargetFocalLength(float offset);\n\n    // Getters\n    const f64& getTargetFocalLength() const { return m_targetFocalLength; }\n    const f64& getSpeed() const { return m_speed; }\n\n    // Setters\n    void setIsDynamic(bool isDynamic) { m_isDynamic = isDynamic; }\n    void setSpeed(f64 speed) { m_speed = speed; }\n    void setTarget(const f64v3& targetFocalPoint, const f32v3& targetDirection,\n                   const f32v3& targetRight, f64 targetFocalLength);\n    void setTargetDirection(const f32v3& targetDirection) { m_targetDirection = targetDirection; }\n    void setTargetRight(const f32v3& targetRight) { m_targetRight = targetRight; }\n    void setTargetFocalPoint(const f64v3& targetFocalPoint) { m_targetFocalPoint = targetFocalPoint; }\n    void setTargetFocalLength(const float& targetFocalLength) { m_targetFocalLength = targetFocalLength; }\n\nprivate:\n    bool m_isDynamic = true;\n    f32v3 m_targetDirection = m_direction; ///< Desired direction\n    f32v3 m_targetRight = m_right; ///< Desired right\n    f64v3 m_targetFocalPoint = m_focalPoint; ///< Target focal position\n    f64 m_targetFocalLength = m_focalLength; ///< Desired focal length\n    f64 m_speed = 0.3; ///< The speed of the camera. 1.0 is the highest\n};\n"
  },
  {
    "path": "SoA/CellularAutomataTask.cpp",
    "content": "#include \"stdafx.h\"\n#include \"CellularAutomataTask.h\"\n\n#include \"CAEngine.h\"\n#include \"Chunk.h\"\n#include \"ChunkMeshManager.h\"\n#include \"VoxPool.h\"\n\nCellularAutomataTask::CellularAutomataTask(ChunkManager* chunkManager,\n                                           PhysicsEngine* physicsEngine,\n                                           Chunk* chunk,\n                                           OPT ChunkMeshManager* meshManager VORB_UNUSED) :\n                                           IThreadPoolTask(CA_TASK_ID),\n                                           _chunk(chunk),\n                                           m_chunkManager(chunkManager),\n                                           m_physicsEngine(physicsEngine) {\n\n    //return;\n\n    //typesToUpdate.reserve(2);\n\n    //if (meshManager) {\n    //    chunk->queuedForMesh = true;\n    //    renderTask = new RenderTask();\n    //    renderTask->init(_chunk, RenderTaskType::DEFAULT, meshManager);\n    //}\n}\n\nvoid CellularAutomataTask::execute(WorkerData* workerData VORB_UNUSED) {\n   // if (workerData->caEngine == nullptr) {\n   //     workerData->caEngine = new CAEngine(m_chunkManager, m_physicsEngine);\n   // }\n   // workerData->caEngine->setChunk(_chunk);\n   // for (auto& type : typesToUpdate) {\n   //     switch (type->getCaAlg()) {\n   //         case CA_ALGORITHM::LIQUID:\n   ////             workerData->caEngine->updateLiquidBlocks(type->getCaIndex());\n   //             break;\n   //         case CA_ALGORITHM::POWDER:\n   ////             workerData->caEngine->updatePowderBlocks(type->getCaIndex());\n   //             break;\n   //         default:\n   //             break;\n   //     }\n   // }\n\n   // if (renderTask) {\n   //     renderTask->execute(workerData);\n   // }\n   //// updateSpawnerBlocks(frameCounter == 0);\n}\n"
  },
  {
    "path": "SoA/CellularAutomataTask.h",
    "content": "///\n/// CellularAutomataTask.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 24 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Implements the celluar automata task for multithreaded physics\n///\n\n#pragma once\n\n#ifndef CellularAutomataTask_h__\n#define CellularAutomataTask_h__\n\n#include <Vorb/IThreadPoolTask.h>\n\n#include \"VoxPool.h\"\n\nclass CaPhysicsType;\nclass Chunk;\nclass ChunkManager;\nclass ChunkMeshManager;\nclass PhysicsEngine;\nclass ChunkMeshTask;\n\n#define CA_TASK_ID 3\n\nenum class CAAlgorithm {\n    NONE = 0,\n    LIQUID = 1,\n    POWDER = 2 \n};\n\nclass CellularAutomataTask : public vcore::IThreadPoolTask<WorkerData> {\npublic:\n    friend class ChunkManager;\n    friend class SphericalVoxelComponentUpdater;\n    /// Constructs the task\n    CellularAutomataTask(ChunkManager* chunkManager,\n                         PhysicsEngine* physicsEngine,\n                         Chunk* chunk,\n                         OPT ChunkMeshManager* meshManager);\n\n    /// Adds a caPhysicsType for update\n    void addCaTypeToUpdate(CaPhysicsType* caType) {\n        typesToUpdate.push_back(caType);\n    }\n\n    /// Executes the task\n    void execute(WorkerData* workerData) override;\n\n    ChunkMeshTask* renderTask = nullptr; ///< A nested to force re-mesh\n\nprivate:\n    std::vector<CaPhysicsType*> typesToUpdate; ///< All the CA types that will be updated by this task\n    Chunk* _chunk = nullptr; ///< The chunk we are updating\n    ChunkManager* m_chunkManager = nullptr;\n    PhysicsEngine* m_physicsEngine = nullptr;\n    ChunkMeshManager* meshManager = nullptr;\n};\n\n#endif // CellularAutomataTask_h__"
  },
  {
    "path": "SoA/Chunk.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Chunk.h\"\n\n#include \"VoxelSpaceConversions.h\"\n\nEvent<ChunkHandle&> Chunk::DataChange;\n\nvoid Chunk::init(WorldCubeFace face) {\n    // Get position from ID\n    m_chunkPosition.pos = i32v3(m_id.x, m_id.y, m_id.z);\n    m_chunkPosition.face = face;\n    m_voxelPosition = VoxelSpaceConversions::chunkToVoxel(m_chunkPosition);\n}\n\nvoid Chunk::initAndFillEmpty(WorldCubeFace face, vvox::VoxelStorageState /*= vvox::VoxelStorageState::INTERVAL_TREE*/) {\n    init(face);\n    IntervalTree<ui16>::LNode blockNode;\n    IntervalTree<ui16>::LNode tertiaryNode;\n    blockNode.set(0, CHUNK_SIZE, 0);\n    tertiaryNode.set(0, CHUNK_SIZE, 0);\n    blocks.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, &blockNode, 1);\n    tertiary.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, &tertiaryNode, 1);\n}\n\nvoid Chunk::setRecyclers(vcore::FixedSizeArrayRecycler<CHUNK_SIZE, ui16>* shortRecycler) {\n    blocks.setArrayRecycler(shortRecycler);\n    tertiary.setArrayRecycler(shortRecycler);\n}\n\nvoid Chunk::updateContainers() {\n    blocks.update(dataMutex);\n    tertiary.update(dataMutex);\n}"
  },
  {
    "path": "SoA/Chunk.h",
    "content": "//\n// NChunk.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 25 May 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef NChunk_h__\n#define NChunk_h__\n\n#include \"Constants.h\"\n#include \"SmartVoxelContainer.hpp\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"PlanetHeightData.h\"\n#include \"MetaSection.h\"\n#include \"ChunkGenerator.h\"\n#include \"ChunkID.h\"\n#include <Vorb/FixedSizeArrayRecycler.hpp>\n\n#if defined(_MSC_VER)\n#define ALIGNED_(x) __declspec(align(x))\n#else\n#define ALIGNED_(x) __attribute__ ((aligned(x)))\n#endif\n\nclass Chunk;\ntypedef Chunk* ChunkPtr;\n\n// TODO(Ben): Move to file\ntypedef ui16 BlockIndex;\n\nclass ChunkGridData {\npublic:\n    ChunkGridData():isLoading(false), isLoaded(false), refCount(1){};\n    ChunkGridData(const ChunkPosition3D& pos):isLoading(false), isLoaded(false), refCount(1)\n    {\n        gridPosition.pos = i32v2(pos.pos.x, pos.pos.z);\n        gridPosition.face = pos.face;\n    }\n\n    ChunkPosition2D gridPosition;\n    PlanetHeightData heightData[CHUNK_LAYER];\n    bool isLoading;\n    bool isLoaded;\n    int refCount;\n};\n\n// TODO(Ben): Can lock two chunks without deadlock worry with checkerboard pattern updates.\n\nclass Chunk {\n    friend class ChunkAccessor;\n    friend class ChunkGenerator;\n    friend class ChunkGrid;\n    friend class ChunkMeshManager;\n    friend class ChunkMeshTask;\n    friend class PagedChunkAllocator;\n    friend class SphericalVoxelComponentUpdater;\npublic:\n    \n    Chunk() : neighbor(), genLevel(ChunkGenLevel::GEN_NONE), pendingGenLevel(ChunkGenLevel::GEN_NONE), isAccessible(false), accessor(nullptr), m_inLoadRange(false),  m_handleState(0), m_handleRefCount(0) {}\n    // Initializes the chunk but does not set voxel data\n    // Should be called after ChunkAccessor sets m_id\n    void init(WorldCubeFace face);\n    // Initializes the chunk and sets all voxel data to 0\n    void initAndFillEmpty(WorldCubeFace face, vvox::VoxelStorageState = vvox::VoxelStorageState::INTERVAL_TREE);\n    void setRecyclers(vcore::FixedSizeArrayRecycler<CHUNK_SIZE, ui16>* shortRecycler);\n    void updateContainers();\n\n    /************************************************************************/\n    /* Getters                                                              */\n    /************************************************************************/\n    const ChunkPosition3D& getChunkPosition() const { return m_chunkPosition; }\n    const VoxelPosition3D& getVoxelPosition() const { return m_voxelPosition; }\n    const ChunkID& getID() const { return m_id; }\n\n    inline ui16 getBlockData(int c) const {\n        return blocks.get(c);\n    }\n    inline ui16 getTertiaryData(int c) const {\n        return tertiary.get(c);\n    }\n    void setBlock(int x, int y, int z, ui16 id) {\n        blocks.set(x + y * CHUNK_LAYER + z * CHUNK_WIDTH, id);\n    }\n\n    // Marks the chunks as dirty and flags for a re-mesh\n    void flagDirty() { isDirty = true; }\n\n    /************************************************************************/\n    /* Members                                                              */\n    /************************************************************************/\n    // Everything else uses this grid data handle\n    ChunkGridData* gridData = nullptr;\n    MetaFieldInformation meta;\n    union {\n        struct {\n            ChunkHandle left;\n            ChunkHandle right;\n            ChunkHandle bottom;\n            ChunkHandle top;\n            ChunkHandle back;\n            ChunkHandle front;\n        } neighbor;\n        ChunkHandle neighbors[6];\n    };\n    volatile ChunkGenLevel genLevel;\n    ChunkGenLevel pendingGenLevel;\n    bool isDirty;\n    f32 distance2; //< Squared distance\n    int numBlocks;\n    // TODO(Ben): reader/writer lock\n    std::mutex dataMutex;\n\n    volatile bool isAccessible;\n\n    // TODO(Ben): Think about data locality.\n    vvox::SmartVoxelContainer<ui16> blocks;\n    vvox::SmartVoxelContainer<ui16> tertiary;\n    // Block indexes where flora must be generated.\n    std::vector<ui16> floraToGenerate;\n    volatile ui32 updateVersion;\n\n    ChunkAccessor* accessor;\n\n    static Event<ChunkHandle&> DataChange;\nprivate:\n    // For generation\n    ChunkGenQueryData m_genQueryData;\n\n    // ui32 m_loadingNeighbors = 0u; ///< Seems like a good idea to get rid of isAccesible\n    ChunkPosition3D m_chunkPosition;\n    VoxelPosition3D m_voxelPosition;\n\n    ui32 m_activeIndex; ///< Position in active list for m_chunkGrid\n    bool m_inLoadRange;\n\n    ChunkID m_id;\n\n    /************************************************************************/\n    /* Chunk Handle Data                                                    */\n    /************************************************************************/\n    std::mutex m_handleMutex;\n    ALIGNED_(4) volatile ui32 m_handleState;\n    ALIGNED_(4) volatile ui32 m_handleRefCount;\n};\n\n#endif // NChunk_h__\n"
  },
  {
    "path": "SoA/ChunkAccessor.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkAccessor.h\"\n\n#include \"ChunkAllocator.h\"\n\nconst ui32 HANDLE_STATE_ALIVE = 2;\n#ifdef FAST_CHUNK_ACCESS\nconst ui32 HANDLE_STATE_DEAD = 0;\nconst ui32 HANDLE_STATE_ACQUIRING = 1;\nconst ui32 HANDLE_STATE_FREEING = 3;\n#endif\n\nChunkHandle::ChunkHandle(const ChunkHandle& other) :\n    m_accessor(other.m_acquired ? other.m_chunk->accessor : other.m_accessor),\n    m_id(other.m_id),\n    m_acquired(false) {\n    // Empty\n}\nChunkHandle& ChunkHandle::operator= (const ChunkHandle& other) {\n    m_acquired = false;\n    m_accessor = other.m_acquired ? other.m_chunk->accessor : other.m_accessor;\n    m_id = other.m_id;\n\n    return *this;\n}\n\nvoid ChunkHandle::acquireSelf() {\n    if (!m_acquired) m_chunk->accessor->acquire(*this);\n}\nChunkHandle ChunkHandle::acquire() {\n    if (m_acquired) {\n        ChunkHandle h(m_chunk->accessor->acquire(*this));\n        h.m_acquired = true;\n        h.m_chunk = m_chunk;\n        return h;\n    } else {\n        return m_accessor->acquire(m_id);\n    }\n}\nvoid ChunkHandle::release() {\n    if (m_acquired) m_chunk->accessor->release(*this);\n}\n\nvoid ChunkAccessor::init(PagedChunkAllocator* allocator) {\n    m_allocator = allocator;\n}\nvoid ChunkAccessor::destroy() {\n    std::unordered_map<ChunkID, ChunkHandle>().swap(m_chunkLookup);\n}\n\n#ifdef FAST_CHUNK_ACCESS\n\nChunkHandle ChunkAccessor::acquire(ChunkID id) {\n    std::unique_lock<std::mutex> lMap(m_lckLookup);\n    auto& it = m_chunkLookup.find(id);\n    if (it == m_chunkLookup.end()) {\n        ChunkHandle& h = m_chunkLookup[id];\n        h.m_chunk = m_allocator->alloc();\n        h->m_handleRefCount = 1;\n        h->m_id = id;\n        h->accessor = this;\n        h->m_handleState = HANDLE_STATE_ALIVE;\n        lMap.unlock();\n        onAdd(ChunkHandle(h));\n        return h;\n    } else {\n        InterlockedIncrement(&it->second->m_handleRefCount);\n        it->second->m_handleState = HANDLE_STATE_ALIVE;\n        return it->second;\n    }\n}\nChunkHandle ChunkAccessor::acquire(ChunkHandle& chunk) {\n    switch (InterlockedCompareExchange(&chunk->m_handleState, HANDLE_STATE_ACQUIRING, HANDLE_STATE_ALIVE)) {\n    case HANDLE_STATE_FREEING:\n        return acquire(chunk->m_id);\n    case HANDLE_STATE_ACQUIRING:\n        InterlockedIncrement(&chunk->m_handleRefCount);\n        return chunk;\n    case HANDLE_STATE_ALIVE:\n        InterlockedIncrement(&chunk->m_handleRefCount);\n        InterlockedCompareExchange(&chunk->m_handleState, HANDLE_STATE_ALIVE, HANDLE_STATE_ACQUIRING);\n        return chunk;\n    default:\n        throw std::invalid_argument(\"INVALID CHUNK HANDLE STATE\");\n    }\n}\nvoid ChunkAccessor::release(ChunkHandle& chunk) {\n    ui32 retries = 0;\n\n    // TODO(Cristian): Heavy thread-safety\n    ui32 currentCount = InterlockedDecrement(&chunk->m_handleRefCount);\nRETEST_CHUNK_LIVELINESS:\n    if (currentCount == 0) {\n        // If the chunk is alive, set it to zombie mode. Otherwise, it's being birthed or already dead.\n        switch (InterlockedCompareExchange(&chunk->m_handleState, HANDLE_STATE_FREEING, HANDLE_STATE_ALIVE)) {\n        case HANDLE_STATE_ALIVE:\n        { // Highlander... there can only be one... killer of chunks\n            std::lock_guard<std::mutex> chunkLock(chunk->m_handleMutex);\n            currentCount = InterlockedDecrement(&chunk->m_handleRefCount);\n            if (chunk->m_handleState == HANDLE_STATE_FREEING) {\n                // We are able to kill this chunk\n                safeRemove(chunk);\n            }\n        }\n        case HANDLE_STATE_FREEING:\n            // Let the other thread do the work\n            break;\n        case HANDLE_STATE_ACQUIRING:\n            // Need to retry\n            std::this_thread::yield();\n            currentCount = chunk->m_handleRefCount;\n            retries++;\n            goto RETEST_CHUNK_LIVELINESS;\n        }\n    }\n\n    // Invalidate the handle\n    chunk.m_chunk = nullptr;\n    if (retries > 2) {\n        printf(\"A lot of release retries occurred: %d\\n\", retries);\n        fflush(stdout);\n    }\n}\n\n#else\n\nChunkHandle ChunkAccessor::acquire(ChunkID id) {\n    bool wasOld;\n    ChunkHandle chunk = safeAdd(id, wasOld);\n\n    if (wasOld) return acquire(chunk);\n\n    chunk.m_acquired = true;\n    return chunk;\n}\nChunkHandle ChunkAccessor::acquire(ChunkHandle& chunk) {\n    std::lock_guard<std::mutex> lChunk(chunk->m_handleMutex);\n    if (chunk->m_handleRefCount == 0) {\n        // We need to re-add the chunk\n        bool wasOld = false;\n        chunk.m_acquired = true;\n        return safeAdd(chunk.m_id, wasOld);\n    } else {\n        ChunkHandle retValue = {};\n        memcpy(&retValue, &chunk, sizeof(ChunkHandle));\n        retValue->m_handleRefCount++;\n        retValue.m_acquired = true;\n        return retValue;\n    }\n}\nvoid ChunkAccessor::release(ChunkHandle& chunk) {\n    std::lock_guard<std::mutex> lChunk(chunk->m_handleMutex);\n    chunk->m_handleRefCount--;\n    if (chunk->m_handleRefCount == 0) {\n        // We need to remove the chunk\n        safeRemove(chunk);\n    }\n    chunk.m_acquired = false;\n    chunk.m_accessor = this;\n}\n\n#endif\n\nChunkHandle ChunkAccessor::safeAdd(ChunkID id, bool& wasOld) {\n    std::unique_lock<std::mutex> l(m_lckLookup);\n    auto it = m_chunkLookup.find(id);\n    if (it == m_chunkLookup.end()) {\n        wasOld = false;\n        ChunkHandle& h = m_chunkLookup[id];\n        h.m_chunk = m_allocator->alloc();\n        h.m_id = id;\n        h->m_id = id;\n        h->accessor = this;\n        h->m_handleState = HANDLE_STATE_ALIVE;\n        h->m_handleRefCount = 1;\n        ChunkHandle tmp(h);\n        l.unlock();\n        onAdd(tmp);\n        return h;\n    } else {\n        wasOld = true;\n        return it->second;\n    }\n}\nvoid ChunkAccessor::safeRemove(ChunkHandle& chunk) {\n    { // TODO(Cristian): This needs to be added to a free-list?\n        std::lock_guard<std::mutex> l(m_lckLookup);\n\n        // Make sure it can't be accessed until acquired again\n        chunk->accessor = nullptr;\n\n        // TODO(Ben): Time based free?\n        m_chunkLookup.erase(chunk.m_id);\n    }\n    // Fire event before deallocating\n    onRemove(chunk);\n    m_allocator->free(chunk.m_chunk);\n}\n"
  },
  {
    "path": "SoA/ChunkAccessor.h",
    "content": "//\n// ChunkAccessor.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 30 Jul 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Fires events for chunk access\n//\n\n#pragma once\n\n#ifndef ChunkAccessor_h__\n#define ChunkAccessor_h__\n\n#include \"Chunk.h\"\n#include \"ChunkHandle.h\"\n\n#include <Vorb/Event.hpp>\n\nclass ChunkAccessor {\n    friend class ChunkHandle;\npublic:\n    void init(PagedChunkAllocator* allocator);\n    void destroy();\n\n    ChunkHandle acquire(ChunkID id);\n\n    size_t getCountAlive() const {\n        return m_chunkLookup.size();\n    }\n\n    Event<ChunkHandle&> onAdd; ///< Called when a handle is added\n    Event<ChunkHandle&> onRemove; ///< Called when a handle is removed\nprivate:\n    ChunkHandle acquire(ChunkHandle& chunk);\n    void release(ChunkHandle& chunk);\n\n    ChunkHandle safeAdd(ChunkID id, bool& wasOld);\n    void safeRemove(ChunkHandle& chunk);\n\n    std::mutex m_lckLookup;\n    std::unordered_map<ChunkID, ChunkHandle> m_chunkLookup;\n    PagedChunkAllocator* m_allocator = nullptr;\n};\n\n#endif // ChunkAccessor_h__\n"
  },
  {
    "path": "SoA/ChunkAllocator.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkAllocator.h\"\n#include \"Chunk.h\"\n\n#define MAX_VOXEL_ARRAYS_TO_CACHE 200\n#define NUM_SHORT_VOXEL_ARRAYS 3\n#define NUM_BYTE_VOXEL_ARRAYS 1\n\n#define INITIAL_UPDATE_VERSION 1\n\nPagedChunkAllocator::PagedChunkAllocator() :\nm_shortFixedSizeArrayRecycler(MAX_VOXEL_ARRAYS_TO_CACHE * NUM_SHORT_VOXEL_ARRAYS) {\n    // Empty\n}\n\nPagedChunkAllocator::~PagedChunkAllocator() {\n    for (auto& page : m_chunkPages) {\n        delete page;\n    }\n}\n\nChunk* PagedChunkAllocator::alloc() {\n    // TODO(Ben): limit\n    std::lock_guard<std::mutex> lock(m_lock);\n\n    // Allocate chunk pages if needed\n    if (m_freeChunks.empty()) {\n        ChunkPage* page = new ChunkPage();\n        m_chunkPages.push_back(page);\n        // Add chunks to free chunks lists\n        for (size_t i = 0; i < CHUNK_PAGE_SIZE; i++) {\n            Chunk* chunk = &page->chunks[CHUNK_PAGE_SIZE - i - 1];\n            chunk->setRecyclers(&m_shortFixedSizeArrayRecycler);\n            m_freeChunks.push_back(chunk);\n        }\n    }\n    // Grab a free chunk\n    Chunk* chunk = m_freeChunks.back();\n    m_freeChunks.pop_back();\n\n    // Set defaults\n    chunk->gridData = nullptr;\n    chunk->m_inLoadRange = false;\n    chunk->numBlocks = 0;\n    chunk->genLevel = ChunkGenLevel::GEN_NONE;\n    chunk->pendingGenLevel = ChunkGenLevel::GEN_NONE;\n    chunk->isAccessible = false;\n    chunk->distance2 = FLT_MAX;\n    chunk->updateVersion = INITIAL_UPDATE_VERSION;\n    memset(chunk->neighbors, 0, sizeof(chunk->neighbors));\n    chunk->m_genQueryData.current = nullptr;\n    return chunk;\n}\n\nvoid PagedChunkAllocator::free(Chunk* chunk) {\n    // TODO(Ben): Deletion if there is a lot?\n    std::lock_guard<std::mutex> lock(m_lock);\n    m_freeChunks.push_back(chunk);\n\n    // Free data\n    chunk->blocks.clear();\n    chunk->tertiary.clear();\n    std::vector<ChunkQuery*>().swap(chunk->m_genQueryData.pending);\n}\n"
  },
  {
    "path": "SoA/ChunkAllocator.h",
    "content": "//\n// ChunkAllocator.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 9 Jun 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Paged memory management system for chunks.\n//\n\n#pragma once\n\n#ifndef ChunkAllocator_h__\n#define ChunkAllocator_h__\n\n#include <Vorb/FixedSizeArrayRecycler.hpp>\n\n#include \"Chunk.h\"\n#include \"Constants.h\"\n\n/*! @brief The chunk allocator.\n */\nclass PagedChunkAllocator {\n    friend class SphericalVoxelComponentUpdater;\npublic:\n    PagedChunkAllocator();\n    ~PagedChunkAllocator();\n\n    typedef void(*MemoryFormatter)(Chunk* chunk, void* memory, void* userData);\n    \n    //void appendExtraSize(size_t s, MemoryFormatter fConstructor);\n\n    /// Gets a new chunk ID\n    Chunk* alloc();\n    /// Frees a chunk\n    void free(Chunk* chunk);\nprotected:\n    static const size_t CHUNK_PAGE_SIZE = 2048;\n    struct ChunkPage {\n        Chunk chunks[CHUNK_PAGE_SIZE];\n    };\n\n    std::vector<Chunk*> m_freeChunks; ///< List of inactive chunks\n    std::vector<ChunkPage*> m_chunkPages; ///< All pages\n    vcore::FixedSizeArrayRecycler<CHUNK_SIZE, ui16> m_shortFixedSizeArrayRecycler; ///< For recycling voxel data\n    std::mutex m_lock; ///< Lock access to free-list\n};\n\n#endif // ChunkAllocator_h__\n"
  },
  {
    "path": "SoA/ChunkGenerator.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkGenerator.h\"\n\n#include \"ChunkAllocator.h\"\n#include \"Chunk.h\"\n#include \"ChunkHandle.h\"\n#include \"ChunkGrid.h\"\n\nvoid ChunkGenerator::init(vcore::ThreadPool<WorkerData>* threadPool,\n                          PlanetGenData* genData,\n                          ChunkGrid* grid) {\n    m_threadPool = threadPool;\n    m_proceduralGenerator.init(genData);\n    m_grid = grid;\n}\n\nvoid ChunkGenerator::submitQuery(ChunkQuery* query) {\n    Chunk& chunk = query->chunk;\n    // Check if its already done\n    if (chunk.genLevel >= query->genLevel) {\n        query->m_isFinished = true;\n        query->m_cond.notify_all();\n        query->chunk.release();\n        if (query->shouldRelease) query->release();\n        return;\n    }\n\n    if (chunk.pendingGenLevel < query->genLevel) {\n        chunk.pendingGenLevel = query->genLevel;\n    }\n    \n    if (!chunk.gridData->isLoaded) {\n        // If this heightmap isn't already loading, send it\n        if (!chunk.gridData->isLoading) {\n            // Send heightmap gen query\n            chunk.gridData->isLoading = true;\n            m_threadPool->addTask(&query->genTask);\n        }\n        // Store as a pending query\n        m_pendingQueries[chunk.gridData].push_back(query);\n    } else {\n        if (chunk.m_genQueryData.current) {\n            // Only one gen query should be active at a time so just store this one\n            chunk.m_genQueryData.pending.push_back(query);\n        } else {\n            // Submit for generation\n            chunk.m_genQueryData.current = query;\n            m_threadPool->addTask(&query->genTask);\n        }\n    }\n}\n\nvoid ChunkGenerator::finishQuery(ChunkQuery* query) {\n    m_finishedQueries.enqueue(query);\n}\n\n// Updates finished queries\nvoid ChunkGenerator::update() {\n#define MAX_QUERIES 100\n    ChunkQuery* queries[MAX_QUERIES];\n    size_t numQueries = m_finishedQueries.try_dequeue_bulk(queries, MAX_QUERIES);\n    for (size_t i = 0; i < numQueries; i++) {\n        ChunkQuery* q = queries[i];\n        Chunk& chunk = q->chunk;\n        chunk.m_genQueryData.current = nullptr;\n        \n        // Check if it was a heightmap gen\n        if (chunk.gridData->isLoading) {\n            chunk.gridData->isLoaded = true;\n            chunk.gridData->isLoading = false;\n\n            // Submit all the pending queries on this grid data\n            auto it = m_pendingQueries.find(chunk.gridData); // TODO(Ben): Should this be shared? ( I don't think it should )\n            for (auto& p : it->second) {\n                submitQuery(p);\n            }\n            m_pendingQueries.erase(it);\n        } else if (chunk.genLevel == GEN_DONE) {\n            // If the chunk is done generating, we can signal all queries as done.\n            for (auto& q2 : chunk.m_genQueryData.pending) {\n                q2->m_isFinished = true;\n                q2->m_cond.notify_all();\n                chunk.isAccessible = true;\n                q2->chunk.release();\n                if (q2->shouldRelease) q2->release();\n            }\n            std::vector<ChunkQuery*>().swap(chunk.m_genQueryData.pending);\n            // Notify listeners that this chunk is finished\n            onGenFinish(q->chunk, q->genLevel);\n            q->chunk.release();\n            if (q->shouldRelease) q->release();\n        } else {\n            // Otherwise possibly only some queries are done\n            for (size_t i = 0; i < chunk.m_genQueryData.pending.size();) {\n                auto q2 = chunk.m_genQueryData.pending[i];\n                if (q2->genLevel <= chunk.genLevel) {\n                    // TODO(Ben): This looks wrong. We don't remove from pending.\n                    q2->m_isFinished = true;\n                    q2->m_cond.notify_all();\n                    chunk.isAccessible = true;\n                    // TODO(Ben): Do we care about order?\n                    chunk.m_genQueryData.pending[i] = chunk.m_genQueryData.pending.back();\n                    chunk.m_genQueryData.pending.pop_back();\n                    q2->chunk.release();\n                    if (q2->shouldRelease) q2->release();\n                } else {\n                    i++;\n                }\n            }\n            // Submit a pending query\n            if (chunk.m_genQueryData.pending.size()) {\n                // Submit for generation\n                q = chunk.m_genQueryData.pending.back();\n                chunk.m_genQueryData.pending.pop_back();\n                chunk.m_genQueryData.current = q;\n                m_threadPool->addTask(&q->genTask);\n            }\n            // Notify listeners that this chunk is finished\n            onGenFinish(q->chunk, q->genLevel);\n            q->chunk.release();\n            if (q->shouldRelease) q->release();\n        }\n    }\n}\n"
  },
  {
    "path": "SoA/ChunkGenerator.h",
    "content": "///\n/// ChunkGenerator.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 10 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// \n///\n\n#pragma once\n\n#ifndef ChunkGenerator_h__\n#define ChunkGenerator_h__\n\n#include <Vorb/ThreadPool.h>\n\n#include \"VoxPool.h\"\n#include \"ProceduralChunkGenerator.h\"\n#include \"PlanetGenData.h\"\n#include \"GenerateTask.h\"\n#include \"ChunkQuery.h\"\n\nclass PagedChunkAllocator;\nclass ChunkGridData;\nclass ChunkGrid;\n\n// Data stored in Chunk and used only by ChunkGenerator\nstruct ChunkGenQueryData {\n    friend class ChunkGenerator;\n    friend class ChunkGrid;\n    friend class PagedChunkAllocator;\nprivate:\n    ChunkQuery* current = nullptr;\n    std::vector<ChunkQuery*> pending;\n};\n\nclass ChunkGenerator {\n    friend class GenerateTask;\npublic:\n    void init(vcore::ThreadPool<WorkerData>* threadPool,\n              PlanetGenData* genData,\n              ChunkGrid* grid);\n    void submitQuery(ChunkQuery* query);\n    void finishQuery(ChunkQuery* query);\n    // Updates finished queries\n    void update();\n\n    Event<ChunkHandle&, ChunkGenLevel> onGenFinish;\nprivate:\n    void tryFlagMeshableNeighbors(ChunkHandle& ch);\n    void flagMeshbleNeighbor(ChunkHandle& n, ui32 bit);\n\n    moodycamel::ConcurrentQueue<ChunkQuery*> m_finishedQueries;\n    std::map < ChunkGridData*, std::vector<ChunkQuery*> >m_pendingQueries; ///< Queries waiting on height map\n\n    ChunkGrid* m_grid = nullptr;\n    ProceduralChunkGenerator m_proceduralGenerator;\n    vcore::ThreadPool<WorkerData>* m_threadPool = nullptr;\n};\n\n#endif // ChunkGenerator_h__\n"
  },
  {
    "path": "SoA/ChunkGrid.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkGrid.h\"\n#include \"Chunk.h\"\n#include \"ChunkAllocator.h\"\n#include \"soaUtils.h\"\n\n#include <Vorb/utils.h>\n\nvoid ChunkGrid::init(WorldCubeFace face,\n                      OPT vcore::ThreadPool<WorkerData>* threadPool,\n                      ui32 generatorsPerRow,\n                      PlanetGenData* genData,\n                      PagedChunkAllocator* allocator) {\n    m_face = face;\n    this->generatorsPerRow = generatorsPerRow;\n    numGenerators = generatorsPerRow * generatorsPerRow;\n    generators = new ChunkGenerator[numGenerators];\n    for (ui32 i = 0; i < numGenerators; i++) {\n        generators[i].init(threadPool, genData, this);\n    }\n    accessor.init(allocator);\n    accessor.onAdd += makeDelegate(this, &ChunkGrid::onAccessorAdd);\n    accessor.onRemove += makeDelegate(this, &ChunkGrid::onAccessorRemove);\n    nodeSetter.grid = this;\n    nodeSetter.threadPool = threadPool;\n}\n\nvoid ChunkGrid::dispose() {\n    accessor.onAdd -= makeDelegate(this, &ChunkGrid::onAccessorAdd);\n    accessor.onRemove -= makeDelegate(this, &ChunkGrid::onAccessorRemove);\n    delete[] generators;\n    generators = nullptr;\n}\n\nChunkQuery* ChunkGrid::submitQuery(const i32v3& chunkPos, ChunkGenLevel genLevel, bool shouldRelease) {\n    ChunkQuery* query;\n    {\n        std::lock_guard<std::mutex> l(m_lckQueryRecycler);\n        query = m_queryRecycler.create();\n    }\n    query->chunkPos = chunkPos;\n    query->genLevel = genLevel;\n    query->shouldRelease = shouldRelease;\n    query->grid = this;\n    query->m_isFinished = false;\n\n    ChunkID id(query->chunkPos);\n    query->chunk = accessor.acquire(id);\n    m_queries.enqueue(query);\n    // TODO(Ben): RACE CONDITION HERE: There is actually a very small chance that\n    // chunk will get freed before the callee can acquire the chunk, if this runs\n    // on another thread.\n    return query;\n}\n\nvoid ChunkGrid::releaseQuery(ChunkQuery* query) {\n    assert(query->grid);\n    query->grid = nullptr;\n    {\n        std::lock_guard<std::mutex> l(m_lckQueryRecycler);\n        m_queryRecycler.recycle(query);\n    }\n}\n\nChunkGridData* ChunkGrid::getChunkGridData(const i32v2& gridPos) {\n    std::lock_guard<std::mutex> l(m_lckGridData);\n    auto it = m_chunkGridDataMap.find(gridPos);\n    if (it == m_chunkGridDataMap.end()) return nullptr;\n    return it->second;\n}\n\nvoid ChunkGrid::update() {\n    // TODO(Ben): Handle generator distribution\n    generators[0].update();\n\n    /* Update Queries */\n    // Needs to be big so we can flush it every frame.\n#define MAX_QUERIES 5000\n    ChunkQuery* queries[MAX_QUERIES];\n    size_t numQueries = m_queries.try_dequeue_bulk(queries, MAX_QUERIES);\n    for (size_t i = 0; i < numQueries; i++) {\n        ChunkQuery* q = queries[i];\n        // TODO(Ben): Handle generator distribution\n        q->genTask.init(q, q->chunk->gridData->heightData, &generators[0]);\n        generators[0].submitQuery(q);\n    }\n    \n    // Place any needed nodes\n    nodeSetter.update();\n}\n\nvoid ChunkGrid::onAccessorAdd(Sender s VORB_MAYBE_UNUSED, ChunkHandle& chunk) {\n    { // Add to active list\n        std::lock_guard<std::mutex> l(m_lckActiveChunks);\n        chunk->m_activeIndex = m_activeChunks.size();\n        m_activeChunks.push_back(chunk);\n    }\n\n    // Init the chunk\n    chunk->init(m_face);\n\n    i32v2 gridPos = chunk->getChunkPosition();\n\n    { // Get grid data\n        std::lock_guard<std::mutex> l(m_lckGridData);\n        // Check and see if the grid data is already allocated here\n        auto it = m_chunkGridDataMap.find(gridPos);\n        if (it == m_chunkGridDataMap.end()) {\n            // If its not allocated, make a new one with a new voxelMapData\n            // TODO(Ben): Cache this\n            chunk->gridData = new ChunkGridData(chunk->getChunkPosition());\n            m_chunkGridDataMap[gridPos] = chunk->gridData;\n        } else {\n            chunk->gridData = it->second;\n            chunk->gridData->refCount++;\n        }\n    }\n}\n\nvoid ChunkGrid::onAccessorRemove(Sender s VORB_MAYBE_UNUSED, ChunkHandle& chunk) {\n    { // Remove from active list\n        std::lock_guard<std::mutex> l(m_lckActiveChunks);\n        m_activeChunks[chunk->m_activeIndex] = m_activeChunks.back();\n        m_activeChunks[chunk->m_activeIndex]->m_activeIndex = chunk->m_activeIndex;\n        m_activeChunks.pop_back();\n    }\n\n    // TODO(Ben): Could be slightly faster with InterlockedDecrement and FSM?\n    { // Remove and possibly free grid data\n        std::unique_lock<std::mutex> l(m_lckGridData);\n        chunk->gridData->refCount--;\n        if (chunk->gridData->refCount == 0) {\n            m_chunkGridDataMap.erase(chunk->getChunkPosition());\n            l.unlock();\n            delete chunk->gridData;\n            chunk->gridData = nullptr;\n        }\n    }\n}\n"
  },
  {
    "path": "SoA/ChunkGrid.h",
    "content": "///\n/// ChunkGrid.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 26 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Grid of chunks for a voxel world\n///\n\n#pragma once\n\n#ifndef ChunkGrid_h__\n#define ChunkGrid_h__\n\n#include <Vorb/concurrentqueue.h>\n#include <Vorb/utils.h>\n#include <Vorb/IDGenerator.h>\n\n#include \"VoxelCoordinateSpaces.h\"\n#include \"ChunkGenerator.h\"\n#include \"Chunk.h\"\n#include \"ChunkAllocator.h\"\n#include \"ChunkAccessor.h\"\n#include \"ChunkHandle.h\"\n\n#include \"VoxelNodeSetter.h\"\n\nclass BlockPack;\n\nclass ChunkGrid {\n    friend class ChunkMeshManager;\npublic:\n    void init(WorldCubeFace face,\n              OPT vcore::ThreadPool<WorkerData>* threadPool,\n              ui32 generatorsPerRow,\n              PlanetGenData* genData,\n              PagedChunkAllocator* allocator);\n    void dispose();\n\n    /// Will generate chunk if it doesn't exist\n    /// @param gridPos: The position of the chunk to get.\n    /// @param genLevel: The required generation level.\n    /// @param shouldRelease: Will automatically release when true.\n    ChunkQuery* submitQuery(const i32v3& chunkPos, ChunkGenLevel genLevel, bool shouldRelease);\n    /// Releases and recycles a query.\n    void releaseQuery(ChunkQuery* query);\n\n    /// Gets a chunkGridData for a specific 2D position\n    /// @param gridPos: The grid position for the data\n    ChunkGridData* getChunkGridData(const i32v2& gridPos);\n\n    // Processes chunk queries and set active chunks\n    void update();\n\n    // Locks and gets active chunks. Must call releaseActiveChunks() later.\n    const std::vector<ChunkHandle>& acquireActiveChunks() { \n        m_lckActiveChunks.lock(); \n        return m_activeChunks;\n    }\n    void releaseActiveChunks() { m_lckActiveChunks.unlock(); }\n\n    ChunkGenerator* generators = nullptr;\n    ui32 generatorsPerRow;\n    ui32 numGenerators;\n\n    ChunkAccessor accessor;\n    BlockPack* blockPack = nullptr; ///< Handle to the block pack for this grid\n\n    VoxelNodeSetter nodeSetter;\n\n    Event<ChunkHandle&> onNeighborsAcquire;\n    Event<ChunkHandle&> onNeighborsRelease;\nprivate:\n    /************************************************************************/\n    /* Event Handlers                                                       */\n    /************************************************************************/\n    void onAccessorAdd(Sender s, ChunkHandle& chunk);\n    void onAccessorRemove(Sender s, ChunkHandle& chunk);\n\n    moodycamel::ConcurrentQueue<ChunkQuery*> m_queries;\n\n    std::mutex m_lckActiveChunks;\n    std::vector<ChunkHandle> m_activeChunks;\n\n    // TODO(Ben): Compare to std::map performance\n    std::mutex m_lckGridData;\n    std::unordered_map<i32v2, ChunkGridData*> m_chunkGridDataMap; ///< 2D grid specific data\n    \n    vcore::IDGenerator<ChunkID> m_idGenerator;\n\n    std::mutex m_lckQueryRecycler;\n    PtrRecycler<ChunkQuery> m_queryRecycler;\n\n\n    WorldCubeFace m_face = FACE_NONE;\n};\n\n#endif // ChunkGrid_h__\n"
  },
  {
    "path": "SoA/ChunkGridRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkGridRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"Frustum.h\"\n#include \"GameRenderParams.h\"\n#include \"ShaderLoader.h\"\n#include \"soaUtils.h\"\n#include \"ChunkGrid.h\"\n\nnamespace {\n    // Default shader source\n    const cString VERT_SRC = R\"(\nuniform mat4 MVP;\n\nin vec3 vPosition;\nin vec4 vTint;\nin vec2 vUV;\n\nout vec4 fTint;\n\nvoid main() {\n    fTint = vTint;\n    gl_Position = MVP * vec4(vPosition, 1.0);\n}\n)\";\n    const cString FRAG_SRC = R\"(\nuniform float unZCoef;\n\nin vec4 fTint;\n\nout vec4 fColor;\n\nvoid main() {\n    fColor = fTint;\n}\n)\";\n}\n\nvoid ChunkGridRenderStage::hook(const GameRenderParams* gameRenderParams) {\n    m_gameRenderParams = gameRenderParams;\n}\n\nvoid ChunkGridRenderStage::init(vui::GameWindow* window VORB_MAYBE_UNUSED, StaticLoadContext& context VORB_MAYBE_UNUSED) {\n    m_vao = 0;\n    m_vbo = 0;\n    m_ibo = 0;\n}\n\n/// NOTE: There is a race condition with _chunkSlots here, but since _chunkSlots is a read only vector,\n/// it should not cause a crash. However data may be partially incorrect.\nvoid ChunkGridRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    if (!m_isActive) return;\n    if (!m_state) return;\n\n    const std::vector<DebugChunkData>& chunkData = m_state->debugChunkData;\n    \n    // Element pattern\n    const ui32 elementBuffer[24] = { 0, 1, 0, 2, 1, 3, 2, 3, 4, 5, 4, 6, 5, 7, 6, 7, 0, 4, 1, 5, 2, 6, 3, 7 };\n    // The mesh that is built from the chunks\n\n    // Build the mesh\n    ColorRGBA8 color;\n    // Used to build each grid\n    std::vector<ChunkGridVertex> vertices(chunkData.size() * 8);\n    std::vector<ui32> indices(chunkData.size() * 24);\n    int numVertices = 0;\n    int numIndices = 0;\n\n    f32v3 posOffset;\n\n    for (auto& data : chunkData) {\n        posOffset = f32v3(f64v3(data.voxelPosition) - m_gameRenderParams->chunkCamera->getPosition());\n\n        if (true /*((chunk->mesh && chunk->mesh->inFrustum) || m_gameRenderParams->chunkCamera->sphereInFrustum(posOffset + f32v3(CHUNK_WIDTH / 2), 28.0f))*/) {\n\n            switch (data.genLevel) {\n                case GEN_DONE:\n                    color = ColorRGBA8(0, 0, 255, 255);\n                    break;\n                case GEN_FLORA:\n                    color = ColorRGBA8(0, 255, 0, 255);\n                    break;\n                default:\n                    color = ColorRGBA8(255, 0, 0, 255);\n                    break;\n            }\n            for (int i = 0; i < 8; i++) {\n                vertices[numVertices + i].color = color;\n                vertices[numVertices + i].uv = f32v2(0.0f, 0.0f);\n            }\n            // Build the indices\n            for (int i = 0; i < 24; i++) {\n                indices.push_back(numVertices + elementBuffer[i]);\n            }\n            \n            // Build the vertices\n            const f32 gmin = 0.01f;\n            const f32 gmax = 31.99f;\n            vertices[numVertices + 0].position = f32v3(gmin, gmin, gmin) + posOffset;\n            vertices[numVertices + 1].position = f32v3(gmax, gmin, gmin) + posOffset;\n            vertices[numVertices + 2].position = f32v3(gmin, gmin, gmax) + posOffset;\n            vertices[numVertices + 3].position = f32v3(gmax, gmin, gmax) + posOffset;\n            vertices[numVertices + 4].position = f32v3(gmin, gmax, gmin) + posOffset;\n            vertices[numVertices + 5].position = f32v3(gmax, gmax, gmin) + posOffset;\n            vertices[numVertices + 6].position = f32v3(gmin, gmax, gmax) + posOffset;\n            vertices[numVertices + 7].position = f32v3(gmax, gmax, gmax) + posOffset;\n\n            numVertices += 8;\n            numIndices += 24;\n        }\n    }\n\n    // Check for non-empty mesh then draw\n    if(numVertices != 0) drawGrid(vertices, indices);\n}\n\nvoid ChunkGridRenderStage::dispose(StaticLoadContext& context VORB_MAYBE_UNUSED) {\n    if(m_vao != 0)  glDeleteVertexArrays(1, &m_vao);\n    if(m_vbo != 0)  glDeleteBuffers(1, &m_vbo);\n    if(m_ibo != 0)  glDeleteBuffers(1, &m_ibo);\n}\n\nvoid ChunkGridRenderStage::drawGrid(std::vector<ChunkGridVertex> vertices, std::vector<ui32> indices) {\n    if(m_vao == 0) glGenVertexArrays(1, &m_vao);\n    glBindVertexArray(m_vao);\n    // Generate and bind VBO\n    if(m_vbo == 0) glGenBuffers(1, &m_vbo);\n    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);\n    // Generate and bind element buffer\n    if(m_ibo == 0) glGenBuffers(1, &m_ibo);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);\n\n    // Set attribute arrays\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n    glEnableVertexAttribArray(2);\n    // Set attribute pointers\n    glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(ChunkGridVertex), offsetptr(ChunkGridVertex, position));\n    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(ChunkGridVertex), offsetptr(ChunkGridVertex, color));\n    glVertexAttribPointer(2, 2, GL_FLOAT, false, sizeof(ChunkGridVertex), offsetptr(ChunkGridVertex, uv));\n    // Unbind VAO\n    glBindVertexArray(0);\n\n    // Upload the data\n    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);\n    glBufferData(GL_ARRAY_BUFFER, sizeof(ChunkGridVertex)* vertices.size(), nullptr, GL_STATIC_DRAW);\n    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(ChunkGridVertex)* vertices.size(), vertices.data());\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    // GLuint numVertices = vertices.size();\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ui32)* indices.size(), nullptr, GL_STATIC_DRAW);\n    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(ui32)* indices.size(), indices.data());\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    GLsizei numIndices = (GLsizei)indices.size();\n\n    // Lazily initialize shader\n    if(!m_program.isCreated()) m_program = ShaderLoader::createProgram(\"ChunkLine\", VERT_SRC, FRAG_SRC);\n\n    // Bind the program\n    m_program.use();\n\n    // Set Matrix\n    glUniformMatrix4fv(m_program.getUniform(\"MVP\"), 1,\n        GL_FALSE,\n        &(m_gameRenderParams->chunkCamera->getViewProjectionMatrix()[0][0]));\n    // Draw the grid     \n    // Bind the VAO\n    glBindVertexArray(m_vao);\n    // Perform draw call\n    glDrawElements(GL_LINES, numIndices, GL_UNSIGNED_INT, nullptr);\n    glBindVertexArray(0);\n\n    // Unuse the program\n    m_program.unuse();\n}\n"
  },
  {
    "path": "SoA/ChunkGridRenderStage.h",
    "content": "///\n/// ChunkGridRenderStage.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 14 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// This file provides the chunk grid render stage,\n/// which is a debug rendering stage for chunk state\n///\n\n#pragma once\n\n#ifndef ChunkGridRenderStage_h__\n#define ChunkGridRenderStage_h__\n\n#include \"IRenderStage.h\"\n#include \"MTRenderState.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\nclass ChunkGrid;\nclass GameRenderParams;\nclass ChunkMemoryManager;\n\nstruct ChunkGridVertex {\npublic:\n    f32v3 position;\n    f32v2 uv;\n    color4 color;\n};\n\nclass ChunkGridRenderStage : public IRenderStage {\npublic:\n    void hook(const GameRenderParams* gameRenderParams);\n\n    // Draws the render stage\n    void setState(const MTRenderState* state) { m_state = state; }\n\n    virtual void init(vui::GameWindow* window, StaticLoadContext& context) override;\n    virtual void render(const Camera* camera) override;\n    virtual void dispose(StaticLoadContext& context) override;\nprivate:\n    void drawGrid(std::vector<ChunkGridVertex> vertices, std::vector<ui32> indices);\n\n    vg::GLProgram m_program;\n    const GameRenderParams* m_gameRenderParams = nullptr; ///< Handle to some shared parameters\n    const MTRenderState* m_state = nullptr;\n\n    GLuint m_vbo;\n    GLuint m_ibo;\n    GLuint m_vao;\n};\n\n#endif // ChunkGridRenderStage_h__\n"
  },
  {
    "path": "SoA/ChunkHandle.h",
    "content": "//\n// ChunkHandle.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 30 Jul 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Does ref counting.\n//\n\n#pragma once\n\n#ifndef ChunkHandle_h__\n\n#include \"ChunkID.h\"\n\nclass Chunk;\nclass ChunkAccessor;\n\nclass ChunkHandle {\n    friend class ChunkAccessor;\npublic:\n    ChunkHandle() : \n        m_chunk(nullptr),\n        m_id({}),\n        m_acquired(false){\n        // Empty\n    }\n    ChunkHandle(const ChunkHandle& other);\n    ChunkHandle& operator= (const ChunkHandle& other);\n    ChunkHandle(ChunkHandle&& other) :\n        m_chunk(other.m_chunk),\n        m_id(other.m_id),\n        m_acquired(other.m_acquired) {\n\n        other.m_acquired = false;\n        other.m_chunk = nullptr;\n        other.m_id = 0;\n    }\n    ChunkHandle& operator= (ChunkHandle&& other) {\n        m_acquired = other.m_acquired;\n        m_chunk = other.m_chunk;\n        m_id = other.m_id;\n\n        other.m_acquired = false;\n        other.m_chunk = nullptr;\n        other.m_id.id = 0;\n\n        return *this;\n    }\n\n    void acquireSelf();\n    ChunkHandle acquire();\n    void release();\n    bool isAquired() const { return m_acquired; }\n\n    operator Chunk&() {\n        return *m_chunk;\n    }\n    operator const Chunk&() const {\n        return *m_chunk;\n    }\n\n    operator Chunk*() {\n        return m_chunk;\n    }\n    operator const Chunk*() const {\n        return m_chunk;\n    }\n\n    Chunk* operator->() {\n        return m_chunk;\n    }\n    const Chunk* operator->() const {\n        return m_chunk;\n    }\n\n    const ChunkID& getID() const {\n        return m_id;\n    }\nprotected:\n    union {\n        Chunk* m_chunk;\n        ChunkAccessor* m_accessor;\n    };\n    ChunkID m_id;\n    bool m_acquired;\n};\n\n#endif // ChunkHandle_h__\n"
  },
  {
    "path": "SoA/ChunkID.h",
    "content": "//\n// ChunkID.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 3 Aug 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// 64 bit ID type for Chunks.\n//\n\n#pragma once\n\n#ifndef ChunkID_h__\n#define ChunkID_h__\n\n#include \"Vorb/types.h\"\n\n// Chunk ID, derived from position.\nstruct ChunkID {\n    ChunkID() : id(0) {};\n    ChunkID(i32 x, i32 y, i32 z) : x(x), y(y), z(z) {};\n    ChunkID(const i32v3& p) : x(p.x), y(p.y), z(p.z) {};\n    ChunkID(ui64 id) : id(id) {};\n    union {\n        struct {\n            i64 x : 24;\n            i64 y : 16;\n            i64 z : 24;\n        };\n        ui64 id;\n    };\n    operator ui64() const { return id; }\n};\n// Hash for ID\ntemplate <>\nstruct std::hash<ChunkID> {\n    size_t operator()(const ChunkID& id) const {\n        std::hash<ui64> h;\n        return h(id.id);\n    }\n};\n\nstatic_assert(sizeof(ChunkID) == 8, \"ChunkID is not 64 bits\");\n\n#endif // ChunkID_h__\n"
  },
  {
    "path": "SoA/ChunkIOManager.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"ChunkIOManager.h\"\n\n#ifdef VORB_OS_WINDOWS\n#include <direct.h> //for mkdir windows\n#include <io.h>\n#endif\n\n#include <fcntl.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <chrono>\n#include <thread>\n\n//#include <ZLIB/zlib.h>\n\n#include \"BlockData.h\"\n#include \"Chunk.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"SoaOptions.h\"\n\nChunkIOManager::ChunkIOManager(const nString& saveDir) :\n    _regionFileManager(saveDir)\n{\n    _isThreadFinished = 0;\n    readWriteThread = NULL;\n    _shouldDisableLoading = 0;\n}\n\nChunkIOManager::~ChunkIOManager()\n{\n    onQuit();\n}\n\nvoid ChunkIOManager::clear() {\n    Chunk*  tmp;\n    _queueLock.lock();\n    //flush queues\n    while (chunksToLoad.try_dequeue(tmp));\n    _queueLock.unlock();\n\n    while (chunksToSave.peek() != nullptr);\n\n    std::this_thread::sleep_for(std::chrono::milliseconds(30));\n\n    while (finishedLoadChunks.try_dequeue(tmp));\n}\n\n\nvoid ChunkIOManager::addToSaveList(Chunk* ch VORB_UNUSED)\n{\n    //if (ch->inSaveThread == 0 && ch->inLoadThread == 0){\n    //    ch->dirty = 0;\n    //    ch->inSaveThread = 1;\n    //    chunksToSave.enqueue(ch);\n    //    _cond.notify_one();\n    //}\n}\n\nvoid ChunkIOManager::addToSaveList(std::vector <Chunk* > &chunks VORB_UNUSED)\n{\n  /*  NChunk* ch;\n    for (size_t i = 0; i < chunks.size(); i++){\n        ch = chunks[i];\n        if (ch->inSaveThread == 0 && ch->inLoadThread == 0){\n            ch->inSaveThread = 1;\n            ch->dirty = 0;\n            chunksToSave.enqueue(ch);\n        }\n    }\n    _cond.notify_one();*/\n}\n\nvoid ChunkIOManager::addToLoadList(Chunk* ch VORB_UNUSED)\n{\n  /*  if (ch->inSaveThread == 0 && ch->inLoadThread == 0){\n        ch->loadStatus = 0;\n        ch->inLoadThread = 1;\n        chunksToLoad.enqueue(ch);\n        _cond.notify_one();\n    }*/\n}\n\nvoid ChunkIOManager::addToLoadList(std::vector <Chunk* > &chunks VORB_UNUSED)\n{\n   /* NChunk* ch;\n\n    if (_shouldDisableLoading) {\n        for (size_t i = 0; i < chunks.size(); i++){\n            chunks[i]->loadStatus = 2;\n            finishedLoadChunks.enqueue(chunks[i]);\n        }\n        return;\n    }\n\n    for (size_t i = 0; i < chunks.size(); i++){\n        ch = chunks[i];\n       \n        if (ch->inSaveThread == 0 && ch->inLoadThread == 0){\n            ch->inLoadThread = true;\n            chunksToLoad.enqueue(ch);\n        }\n        else{\n            std::cout << \"ERROR: Tried to add chunk to load list and its in a thread! : \" << (int)ch->inSaveThread << \" \" << (int)ch->inLoadThread << \" \" << ch->voxelPosition.z << std::endl;\n        }\n    }\n    _cond.notify_one();*/\n}\n\nvoid ChunkIOManager::readWriteChunks()\n{\n    //std::unique_lock<std::mutex> queueLock(_queueLock);\n    //NChunk* ch;\n\n    //nString reg;\n\n    //while (!_isDone){\n    //    if (_isDone){\n    //        _regionFileManager.clear();\n    //        queueLock.unlock();\n    //        _isThreadFinished = 1;\n    //        return;\n    //    }\n    //    _regionFileManager.flush();\n    //    _cond.wait(queueLock); //wait for a notification that queue is not empty\n\n    //    if (_isDone){\n    //        _regionFileManager.clear();\n    //        _isThreadFinished = 1;\n    //        queueLock.unlock();\n    //        return;\n    //    }\n    //    queueLock.unlock();\n\n    //    // All tasks\n    //    while (chunksToLoad.try_dequeue(ch) || chunksToSave.try_dequeue(ch)) {\n    //        if (ch->getState() == ChunkStates::LOAD) {\n    //            if (1 || _regionFileManager.tryLoadChunk(ch) == false) {\n    //                ch->loadStatus = 1;\n    //            }\n\n    //            finishedLoadChunks.enqueue(ch);\n    //        } else { //save\n    //           // _regionFileManager.saveChunk(ch);\n    //            ch->inSaveThread = 0; //race condition?\n    //        }\n    //       \n    //    }\n\n    //    queueLock.lock();\n    //}\n}\n\nvoid ChunkIOManager::beginThread()\n{\n    _isDone = 0;\n    _isThreadFinished = 0;\n    readWriteThread = NULL;\n    readWriteThread = new std::thread(&ChunkIOManager::readWriteChunks, this);\n}\n\nvoid ChunkIOManager::onQuit()\n{\n\n    clear();\n\n    _queueLock.lock();\n    _isDone = 1;\n    _queueLock.unlock();\n    _cond.notify_one();\n    if (readWriteThread != NULL && readWriteThread->joinable()) readWriteThread->join();\n    delete readWriteThread;\n    readWriteThread = NULL;\n}\n\nbool ChunkIOManager::saveVersionFile() {\n    return _regionFileManager.saveVersionFile();\n}\n\nbool ChunkIOManager::checkVersion() {\n    return _regionFileManager.checkVersion();\n}"
  },
  {
    "path": "SoA/ChunkIOManager.h",
    "content": "#pragma once\n#include <condition_variable>\n#include <mutex>\n#include <queue>\n#include <thread>\n\n#include \"RegionFileManager.h\"\n#include \"readerwriterqueue.h\"\n\nclass Chunk;\n\nclass ChunkIOManager{\npublic:\n    ChunkIOManager(const nString& saveDir);\n    ~ChunkIOManager();\n    void clear();\n\n    void addToSaveList(Chunk*  ch);\n    void addToSaveList(std::vector<Chunk* >& chunks);\n    void addToLoadList(Chunk*  ch);\n    void addToLoadList(std::vector<Chunk* >& chunks);\n\n    void beginThread();\n\n    void onQuit();\n\n    void setDisableLoading(bool disableLoading) { _shouldDisableLoading = disableLoading; }\n\n    bool saveVersionFile();\n    bool checkVersion();\n\n    moodycamel::ReaderWriterQueue<Chunk* > chunksToLoad;\n    moodycamel::ReaderWriterQueue<Chunk* > chunksToSave;\n    std::thread* readWriteThread;\n    moodycamel::ReaderWriterQueue<Chunk* > finishedLoadChunks;\nprivate:\n    RegionFileManager _regionFileManager;\n\n    void readWriteChunks(); //used by the thread\n\n    std::mutex _queueLock;\n    std::condition_variable _cond;\n\n    bool _isDone;\n    bool _isThreadFinished;\n    bool _shouldDisableLoading;\n};"
  },
  {
    "path": "SoA/ChunkMesh.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkMesh.h\"\n\n#include \"BlockData.h\"\n#include \"Chunk.h\"\n#include \"ChunkMeshTask.h\"\n\nKEG_ENUM_DEF(MeshType, MeshType, e) {\n    e.addValue(\"none\", MeshType::NONE);\n    e.addValue(\"cube\", MeshType::BLOCK);\n    e.addValue(\"leaves\", MeshType::LEAVES);\n    e.addValue(\"triangle\", MeshType::TRIANGLE);\n    e.addValue(\"cross\", MeshType::CROSSFLORA);\n    e.addValue(\"liquid\", MeshType::LIQUID);\n    e.addValue(\"flat\", MeshType::FLAT);\n}\n\nChunkMeshData::ChunkMeshData() : type(MeshTaskType::DEFAULT) {\n    // Empty\n}\n\nChunkMeshData::ChunkMeshData(MeshTaskType type) : type(type) {\n    // Empty\n}\n\nvoid ChunkMeshData::addTransQuad(const i8v3& pos) {\n    transQuadPositions.push_back(pos);\n\n    int size = transQuadIndices.size();\n    transQuadIndices.resize(size + 6);\n    transQuadIndices[size++] = transVertIndex;\n    transQuadIndices[size++] = transVertIndex + 1;\n    transQuadIndices[size++] = transVertIndex + 2;\n    transQuadIndices[size++] = transVertIndex + 2;\n    transQuadIndices[size++] = transVertIndex + 3;\n    transQuadIndices[size] = transVertIndex;\n\n    transVertIndex += 4;\n}\n"
  },
  {
    "path": "SoA/ChunkMesh.h",
    "content": "#pragma once\n#include \"Vertex.h\"\n#include \"BlockTextureMethods.h\"\n#include \"ChunkHandle.h\"\n#include <Vorb/io/Keg.h>\n#include <Vorb/graphics/gtypes.h>\n\nenum class MeshType {\n    NONE, \n    BLOCK, \n    LEAVES, \n    TRIANGLE,\n    CROSSFLORA, \n    LIQUID,\n    FLAT \n};\nKEG_ENUM_DECL(MeshType);\n\nenum class MeshTaskType;\n\nclass Block;\nclass Chunk;\nclass ChunkGridData;\nclass ChunkMesh;\nclass ChunkMeshTask;\n\nclass ChunkMeshRenderData {\npublic:\n    // TODO(Ben): These can be ui16\n    i32 pxVboOff = 0;\n    i32 pxVboSize = 0; \n    i32 nxVboOff = 0;\n    i32 nxVboSize = 0;\n    i32 pzVboOff = 0;\n    i32 pzVboSize = 0;\n    i32 nzVboOff = 0;\n    i32 nzVboSize = 0;\n    i32 pyVboOff = 0;\n    i32 pyVboSize = 0;\n    i32 nyVboOff = 0;\n    i32 nyVboSize = 0;\n    i32 transVboSize = 0;\n    i32 cutoutVboSize = 0;\n    i32 highestY = INT_MIN;\n    i32 lowestY = INT_MAX;\n    i32 highestX = INT_MIN;\n    i32 lowestX = INT_MAX;\n    i32 highestZ = INT_MIN;\n    i32 lowestZ = INT_MAX;\n    ui32 indexSize = 0;\n    ui32 waterIndexSize = 0;\n};\n\nstruct VoxelQuad {\n    VoxelQuad() {}\n\n    VoxelQuad(VoxelQuad const &that)\n    {\n        for(size_t i=0; i<4; i++)\n            verts[i]=that.verts[i];\n    }\n\n    ~VoxelQuad()\n    {\n        v.v0.BlockVertex::~BlockVertex();\n        v.v1.BlockVertex::~BlockVertex();\n        v.v2.BlockVertex::~BlockVertex();\n        v.v3.BlockVertex::~BlockVertex(); \n    }\n\n    union {\n        struct{\n            BlockVertex v0;\n            BlockVertex v1;\n            BlockVertex v2;\n            union {\n                BlockVertex v3;\n                ui16 replaceQuad; // Quad that replaces this quad\n            };\n        } v;\n        BlockVertex verts[4];\n    };\n};\n\nclass ChunkMeshData\n{\npublic:\n    ChunkMeshData();\n    ChunkMeshData(MeshTaskType type);\n\n    void addTransQuad(const i8v3& pos);\n\n    ChunkMeshRenderData chunkMeshRenderData;\n\n    // TODO(Ben): Could use a contiguous buffer for this?\n    std::vector <VoxelQuad> opaqueQuads;\n    std::vector <VoxelQuad> transQuads;\n    std::vector <VoxelQuad> cutoutQuads;\n    std::vector <LiquidVertex> waterVertices;\n    MeshTaskType type;\n\n    //*** Transparency info for sorting ***\n    ui32 transVertIndex = 0;\n    std::vector <i8v3> transQuadPositions;\n    std::vector <ui32> transQuadIndices;\n};\n\n#define ACTIVE_MESH_INDEX_NONE UINT_MAX\n\nclass ChunkMesh\n{\npublic:\n    ChunkMesh() : vboID(0), waterVboID(0),\n        cutoutVboID(0), transVboID(0),\n        vaoID(0), transVaoID(0),\n        cutoutVaoID(0), waterVaoID(0) {}\n\n    ChunkMeshRenderData renderData;\n    union {\n        struct {\n            VGVertexBuffer vboID;\n            VGVertexBuffer waterVboID;\n            VGVertexBuffer cutoutVboID;\n            VGVertexBuffer transVboID;\n        };\n        VGVertexBuffer vbos[4];\n    };\n    union {\n        struct {\n            VGVertexArray vaoID;\n            VGVertexArray transVaoID;\n            VGVertexArray cutoutVaoID;\n            VGVertexArray waterVaoID;\n        };\n        VGVertexArray vaos[4];\n    };\n\n    f64 distance2 = 32.0;\n    f64v3 position;\n    ui32 activeMeshesIndex = ACTIVE_MESH_INDEX_NONE; ///< Index into active meshes array\n    ui32 updateVersion;\n    bool inFrustum = false;\n    bool needsSort = true;\n    ChunkID id;\n\n    //*** Transparency info for sorting ***\n    VGIndexBuffer transIndexID = 0;\n    std::vector<i8v3> transQuadPositions;\n    std::vector<ui32> transQuadIndices;\n};\n"
  },
  {
    "path": "SoA/ChunkMeshManager.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkMeshManager.h\"\n\n#include \"ChunkMesh.h\"\n#include \"ChunkMeshTask.h\"\n#include \"ChunkMesher.h\"\n#include \"ChunkRenderer.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"soaUtils.h\"\n\n#define MAX_UPDATES_PER_FRAME 300\n\nChunkMeshManager::ChunkMeshManager(vcore::ThreadPool<WorkerData>* threadPool, BlockPack* blockPack) {\n    m_threadPool = threadPool;\n    m_blockPack = blockPack;\n    SpaceSystemAssemblages::onAddSphericalVoxelComponent += makeDelegate(this, &ChunkMeshManager::onAddSphericalVoxelComponent);\n    SpaceSystemAssemblages::onRemoveSphericalVoxelComponent += makeDelegate(this, &ChunkMeshManager::onRemoveSphericalVoxelComponent);\n}\n\nvoid ChunkMeshManager::update(const f64v3& cameraPosition, bool shouldSort) {\n    ChunkMeshUpdateMessage updateBuffer[MAX_UPDATES_PER_FRAME];\n    size_t numUpdates;\n    if ((numUpdates = m_messages.try_dequeue_bulk(updateBuffer, MAX_UPDATES_PER_FRAME))) {\n        for (size_t i = 0; i < numUpdates; i++) {\n            updateMesh(updateBuffer[i]);\n        }\n    }\n\n    // Update pending meshes\n    {\n        std::lock_guard<std::mutex> l(m_lckPendingMesh);\n        for (auto it = m_pendingMesh.begin(); it != m_pendingMesh.end();) {\n            ChunkMeshTask* task = createMeshTask(it->second);\n            if (task) {\n                {\n                    std::lock_guard<std::mutex> l(m_lckActiveChunks);\n\n                    auto iter=m_activeChunks.find(it->first);\n\n                    assert(iter!=m_activeChunks.end());\n                    iter->second->updateVersion = it->second->updateVersion;\n                }\n                m_threadPool->addTask(task);\n                it->second.release();\n                m_pendingMesh.erase(it++);\n            } else {\n                ++it;\n            }\n        }\n    }\n\n    // TODO(Ben): This is redundant with the chunk manager! Find a way to share! (Pointer?)\n    updateMeshDistances(cameraPosition);\n    if (shouldSort) {\n        \n    }\n}\n\nvoid ChunkMeshManager::destroy() {\n    std::vector <ChunkMesh*>().swap(m_activeChunkMeshes);\n    moodycamel::ConcurrentQueue<ChunkMeshUpdateMessage>().swap(m_messages);\n    std::unordered_map<ChunkID, ChunkMesh*>().swap(m_activeChunks);\n}\n\nChunkMesh* ChunkMeshManager::createMesh(ChunkHandle& h) {\n    ChunkMesh* mesh;\n    { // Get a free mesh\n        std::lock_guard<std::mutex> l(m_lckMeshRecycler);\n        mesh = m_meshRecycler.create();\n    }\n    mesh->id = h.getID();\n\n    // Set the position\n    mesh->position = h->m_voxelPosition;\n\n    // Zero buffers\n    memset(mesh->vbos, 0, sizeof(mesh->vbos));\n    memset(mesh->vaos, 0, sizeof(mesh->vaos));\n    mesh->transIndexID = 0;\n    mesh->activeMeshesIndex = ACTIVE_MESH_INDEX_NONE;\n\n    { // Register chunk as active and give it a mesh\n        std::lock_guard<std::mutex> l(m_lckActiveChunks);\n        m_activeChunks[h.getID()] = mesh;\n    }\n\n    return mesh;\n}\n\nChunkMeshTask* ChunkMeshManager::createMeshTask(ChunkHandle& chunk) {\n    ChunkHandle& left = chunk->neighbor.left;\n    ChunkHandle& right = chunk->neighbor.right;\n    ChunkHandle& bottom = chunk->neighbor.bottom;\n    ChunkHandle& top = chunk->neighbor.top;\n    ChunkHandle& back = chunk->neighbor.back;\n    ChunkHandle& front = chunk->neighbor.front;\n\n    if (!left.isAquired() || !right.isAquired() || !back.isAquired() ||\n        !front.isAquired() || !bottom.isAquired() || !top.isAquired()) {\n        std::cout << \"NOT ACQUIRED\";\n    }\n\n    if (left->genLevel != GEN_DONE || right->genLevel != GEN_DONE ||\n        back->genLevel != GEN_DONE || front->genLevel != GEN_DONE ||\n        bottom->genLevel != GEN_DONE || top->genLevel != GEN_DONE) return nullptr;\n\n    // TODO(Ben): Recycler\n    ChunkMeshTask* meshTask = new ChunkMeshTask;\n    meshTask->init(chunk, MeshTaskType::DEFAULT, m_blockPack, this);\n\n    // Set dependencies\n    meshTask->neighborHandles[NEIGHBOR_HANDLE_LEFT] = left.acquire();\n    meshTask->neighborHandles[NEIGHBOR_HANDLE_RIGHT] = right.acquire();\n    meshTask->neighborHandles[NEIGHBOR_HANDLE_FRONT] = front.acquire();\n    meshTask->neighborHandles[NEIGHBOR_HANDLE_BACK] = back.acquire();\n    meshTask->neighborHandles[NEIGHBOR_HANDLE_TOP] = top.acquire();\n    meshTask->neighborHandles[NEIGHBOR_HANDLE_BOT] = bottom.acquire();\n    return meshTask;\n}\n\nvoid ChunkMeshManager::disposeMesh(ChunkMesh* mesh) {\n    // De-allocate buffer objects\n    glDeleteBuffers(4, mesh->vbos);\n    glDeleteVertexArrays(4, mesh->vaos);\n    if (mesh->transIndexID) glDeleteBuffers(1, &mesh->transIndexID);\n\n    { // Remove from mesh list\n        std::lock_guard<std::mutex> l(lckActiveChunkMeshes);\n        if (mesh->activeMeshesIndex != ACTIVE_MESH_INDEX_NONE) {\n            m_activeChunkMeshes[mesh->activeMeshesIndex] = m_activeChunkMeshes.back();\n            m_activeChunkMeshes[mesh->activeMeshesIndex]->activeMeshesIndex = mesh->activeMeshesIndex;\n            m_activeChunkMeshes.pop_back();\n            mesh->activeMeshesIndex = ACTIVE_MESH_INDEX_NONE;\n        }\n    }\n    \n    { // Release the mesh\n        std::lock_guard<std::mutex> l(m_lckMeshRecycler);\n        m_meshRecycler.recycle(mesh);\n    }\n}\n\nvoid ChunkMeshManager::updateMesh(ChunkMeshUpdateMessage& message) {\n    ChunkMesh *mesh;\n    { // Get the mesh object\n        std::lock_guard<std::mutex> l(m_lckActiveChunks);\n        auto it = m_activeChunks.find(message.chunkID);\n        if (it == m_activeChunks.end()) {\n            delete message.meshData;\n            return; /// The mesh was already released, so ignore!\n        }\n        mesh = it->second;\n    }\n    \n    if (ChunkMesher::uploadMeshData(*mesh, message.meshData)) {\n        // Add to active list if its not there\n        std::lock_guard<std::mutex> l(lckActiveChunkMeshes);\n        if (mesh->activeMeshesIndex == ACTIVE_MESH_INDEX_NONE) {\n            mesh->activeMeshesIndex = m_activeChunkMeshes.size();\n            mesh->updateVersion = 0;\n            m_activeChunkMeshes.push_back(mesh);\n        }\n    } else {\n        // Remove from active list\n        std::lock_guard<std::mutex> l(lckActiveChunkMeshes);\n        if (mesh->activeMeshesIndex != ACTIVE_MESH_INDEX_NONE) {\n            m_activeChunkMeshes[mesh->activeMeshesIndex] = m_activeChunkMeshes.back();\n            m_activeChunkMeshes[mesh->activeMeshesIndex]->activeMeshesIndex = mesh->activeMeshesIndex;\n            m_activeChunkMeshes.pop_back();\n            mesh->activeMeshesIndex = ACTIVE_MESH_INDEX_NONE;\n        }\n    }\n\n    // TODO(Ben): come on...\n    delete message.meshData;\n}\n\nvoid ChunkMeshManager::updateMeshDistances(const f64v3& cameraPosition) {\n    static const f64v3 CHUNK_DIMS(CHUNK_WIDTH);\n    // TODO(Ben): Spherical instead?\n    std::lock_guard<std::mutex> l(lckActiveChunkMeshes);\n    for (auto& mesh : m_activeChunkMeshes) { //update distances for all chunk meshes\n        //calculate distance\n        f64v3 closestPoint = getClosestPointOnAABB(cameraPosition, mesh->position, CHUNK_DIMS);\n        // Omit sqrt for faster calculation\n        mesh->distance2 = selfDot(closestPoint - cameraPosition);\n    }\n}\n\nvoid ChunkMeshManager::onAddSphericalVoxelComponent(Sender s VORB_MAYBE_UNUSED, SphericalVoxelComponent& cmp, vecs::EntityID e VORB_MAYBE_UNUSED) {\n    for (ui32 i = 0; i < 6; i++) {\n        for (ui32 j = 0; j < cmp.chunkGrids[i].numGenerators; j++) {\n            cmp.chunkGrids[i].generators[j].onGenFinish += makeDelegate(this, &ChunkMeshManager::onGenFinish);\n        }\n        cmp.chunkGrids[i].onNeighborsAcquire += makeDelegate(this, &ChunkMeshManager::onNeighborsAcquire);\n        cmp.chunkGrids[i].onNeighborsRelease += makeDelegate(this, &ChunkMeshManager::onNeighborsRelease);\n        Chunk::DataChange += makeDelegate(this, &ChunkMeshManager::onDataChange);\n    }\n}\n\nvoid ChunkMeshManager::onRemoveSphericalVoxelComponent(Sender s VORB_MAYBE_UNUSED, SphericalVoxelComponent& cmp, vecs::EntityID e VORB_MAYBE_UNUSED) {\n    for (ui32 i = 0; i < 6; i++) {\n        for (ui32 j = 0; j < cmp.chunkGrids[i].numGenerators; j++) {\n            cmp.chunkGrids[i].generators[j].onGenFinish -= makeDelegate(this, &ChunkMeshManager::onGenFinish);\n        }\n        cmp.chunkGrids[i].onNeighborsAcquire -= makeDelegate(this, &ChunkMeshManager::onNeighborsAcquire);\n        cmp.chunkGrids[i].onNeighborsRelease -= makeDelegate(this, &ChunkMeshManager::onNeighborsRelease);\n        Chunk::DataChange -= makeDelegate(this, &ChunkMeshManager::onDataChange);\n    }\n}\n\nvoid ChunkMeshManager::onGenFinish(Sender s VORB_MAYBE_UNUSED, ChunkHandle& chunk, ChunkGenLevel gen VORB_MAYBE_UNUSED) {\n    // Check if can be meshed.\n    if (chunk->genLevel == GEN_DONE && chunk->neighbor.left.isAquired() && chunk->numBlocks) {\n        std::lock_guard<std::mutex> l(m_lckPendingMesh);\n        m_pendingMesh.emplace(chunk.getID(), chunk.acquire());\n    }\n}\n\nvoid ChunkMeshManager::onNeighborsAcquire(Sender s VORB_UNUSED, ChunkHandle& chunk) {\n    createMesh(chunk);\n    // Check if can be meshed.\n    if (chunk->genLevel == GEN_DONE && chunk->numBlocks) {\n        std::lock_guard<std::mutex> l(m_lckPendingMesh);\n        m_pendingMesh.emplace(chunk.getID(), chunk.acquire());\n    }\n}\n\nvoid ChunkMeshManager::onNeighborsRelease(Sender s VORB_MAYBE_UNUSED, ChunkHandle& chunk) {\n    // Destroy message\n    ChunkMesh* mesh;\n    {\n        std::lock_guard<std::mutex> l(m_lckActiveChunks);\n        auto it = m_activeChunks.find(chunk.getID());\n        if (it == m_activeChunks.end()) {\n            return;\n        } else {\n            mesh = it->second;\n            m_activeChunks.erase(it);\n        }\n    }\n    {\n        std::lock_guard<std::mutex> l(m_lckPendingMesh);\n        auto it = m_pendingMesh.find(chunk.getID());\n        if (it != m_pendingMesh.end()) {\n            it->second.release();\n            m_pendingMesh.erase(it);\n        }\n    }\n\n    disposeMesh(mesh);\n}\n\nvoid ChunkMeshManager::onDataChange(Sender s VORB_MAYBE_UNUSED, ChunkHandle& chunk) {\n    // Have to have neighbors\n    // TODO(Ben): Race condition with neighbor removal here.\n    if (chunk->neighbor.left.isAquired()) {\n        std::lock_guard<std::mutex> l(m_lckPendingMesh);\n        m_pendingMesh.emplace(chunk.getID(), chunk.acquire());\n    }\n}\n"
  },
  {
    "path": "SoA/ChunkMeshManager.h",
    "content": "///\n/// ChunkMeshManager.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 26 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Handles the updating and deallocation of\n/// chunk meshes.\n///\n\n#pragma once\n\n#ifndef ChunkMeshManager_h__\n#define ChunkMeshManager_h__\n\n#include \"Vorb/concurrentqueue.h\"\n#include \"Chunk.h\"\n#include \"ChunkMesh.h\"\n#include \"SpaceSystemAssemblages.h\"\n#include <mutex>\n\nstruct ChunkMeshUpdateMessage {\n    ChunkID chunkID;\n    ChunkMeshData* meshData = nullptr;\n};\n\nclass ChunkMeshManager {\npublic:\n    ChunkMeshManager(vcore::ThreadPool<WorkerData>* threadPool, BlockPack* blockPack);\n    /// Updates the meshManager, uploading any needed meshes\n    void update(const f64v3& cameraPosition, bool shouldSort);\n    /// Adds a mesh for updating\n    void sendMessage(const ChunkMeshUpdateMessage& message) { m_messages.enqueue(message); }\n    /// Destroys all meshes\n    void destroy();\n\n    // Be sure to lock lckActiveChunkMeshes\n    const std::vector <ChunkMesh*>& getChunkMeshes() { return m_activeChunkMeshes; }\n    std::mutex lckActiveChunkMeshes;\nprivate:\n    VORB_NON_COPYABLE(ChunkMeshManager);\n\n    ChunkMesh* createMesh(ChunkHandle& h);\n\n    ChunkMeshTask* createMeshTask(ChunkHandle& chunk);\n\n    void disposeMesh(ChunkMesh* mesh);\n\n    /// Uploads a mesh and adds to list if needed\n    void updateMesh(ChunkMeshUpdateMessage& message);\n\n    void updateMeshDistances(const f64v3& cameraPosition);\n\n    /************************************************************************/\n    /* Event Handlers                                                       */\n    /************************************************************************/\n    void onAddSphericalVoxelComponent(Sender s, SphericalVoxelComponent& cmp, vecs::EntityID e);\n    void onRemoveSphericalVoxelComponent(Sender s, SphericalVoxelComponent& cmp, vecs::EntityID e);\n    void onGenFinish(Sender s, ChunkHandle& chunk, ChunkGenLevel gen);\n    void onNeighborsAcquire(Sender s, ChunkHandle& chunk);\n    void onNeighborsRelease(Sender s, ChunkHandle& chunk);\n    void onDataChange(Sender s, ChunkHandle& chunk);\n\n    /************************************************************************/\n    /* Members                                                              */\n    /************************************************************************/\n    std::vector<ChunkMesh*> m_activeChunkMeshes; ///< Meshes that should be drawn\n    moodycamel::ConcurrentQueue<ChunkMeshUpdateMessage> m_messages; ///< Lock-free queue of messages\n   \n    BlockPack* m_blockPack = nullptr;\n    vcore::ThreadPool<WorkerData>* m_threadPool = nullptr;\n\n    std::mutex m_lckPendingMesh;\n    std::map<ChunkID, ChunkHandle> m_pendingMesh;\n\n    std::mutex m_lckMeshRecycler;\n    PtrRecycler<ChunkMesh> m_meshRecycler;\n    std::mutex m_lckActiveChunks;\n    std::unordered_map<ChunkID, ChunkMesh*> m_activeChunks; ///< Stores chunk IDs that have meshes\n};\n\n#endif // ChunkMeshManager_h__\n"
  },
  {
    "path": "SoA/ChunkMeshTask.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkMeshTask.h\"\n\n#include <Vorb/ThreadPool.h>\n\n#include \"BlockData.h\"\n#include \"BlockPack.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkMesher.h\"\n#include \"GameManager.h\"\n#include \"Chunk.h\"\n#include \"VoxelLightEngine.h\"\n#include \"VoxelUtils.h\"\n\nvoid ChunkMeshTask::execute(WorkerData* workerData) {\n    // Mesh updates are accompanied by light updates // TODO(Ben): Seems wasteful.\n    if (workerData->voxelLightEngine == nullptr) {\n        workerData->voxelLightEngine = new VoxelLightEngine();\n    }\n    \n    // TODO(Ben): Lighting\n    // updateLight(workerData->voxelLightEngine);\n    \n    // Lazily allocate chunkMesher // TODO(Ben): Seems wasteful.\n    if (workerData->chunkMesher == nullptr) {\n        workerData->chunkMesher = new ChunkMesher;\n        workerData->chunkMesher->init(blockPack);\n    }\n    // Prepare message\n    ChunkMeshUpdateMessage msg;\n    msg.chunkID = chunk.getID();\n\n    // Pre-processing\n    workerData->chunkMesher->prepareDataAsync(chunk, neighborHandles);\n\n    // Create the actual mesh\n    msg.meshData = workerData->chunkMesher->createChunkMeshData(type);\n\n    // Send it for update\n    meshManager->sendMessage(msg);\n}\n\nvoid ChunkMeshTask::init(ChunkHandle& ch, MeshTaskType cType, const BlockPack* blockPack, ChunkMeshManager* meshManager) {\n    type = cType;\n    chunk = ch.acquire();\n    this->blockPack = blockPack;\n    this->meshManager = meshManager;\n}\n\n// TODO(Ben): uhh\nvoid ChunkMeshTask::updateLight(VoxelLightEngine* voxelLightEngine VORB_UNUSED) {\n    /* if (chunk->sunRemovalList.size()) {\n         voxelLightEngine->calculateSunlightRemoval(chunk);\n         }\n         if (chunk->sunExtendList.size()) {\n         voxelLightEngine->calculateSunlightExtend(chunk);\n         }\n         voxelLightEngine->calculateLight(chunk);*/\n}\n"
  },
  {
    "path": "SoA/ChunkMeshTask.h",
    "content": "///\n/// RenderTask.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// This file has the implementation of a render task for SoA\n///\n\n#pragma once\n\n#ifndef RenderTask_h__\n#define RenderTask_h__\n\n#include <Vorb/IThreadPoolTask.h>\n\n#include \"ChunkHandle.h\"\n#include \"Constants.h\"\n#include \"VoxPool.h\"\n\nclass Chunk;\nclass ChunkGridData;\nclass ChunkMesh;\nclass ChunkMeshData;\nclass ChunkMeshManager;\nclass VoxelLightEngine;\nclass BlockPack;\n\nenum class MeshTaskType { DEFAULT, LIQUID };\n\nenum MeshNeighborHandles {\n    NEIGHBOR_HANDLE_LEFT = 0,\n    NEIGHBOR_HANDLE_RIGHT,\n    NEIGHBOR_HANDLE_FRONT,\n    NEIGHBOR_HANDLE_BACK,\n    NEIGHBOR_HANDLE_TOP,\n    NEIGHBOR_HANDLE_BOT,\n    NUM_NEIGHBOR_HANDLES ///< Has to be last\n};\n\n#define CHUNK_MESH_TASK_ID 0\n\n// Represents A Mesh Creation Task\nclass ChunkMeshTask : public vcore::IThreadPoolTask<WorkerData> {\npublic:\n    ChunkMeshTask() : vcore::IThreadPoolTask<WorkerData>(CHUNK_MESH_TASK_ID) {}\n\n    // Executes the task\n    void execute(WorkerData* workerData) override;\n\n    // Initializes the task\n    void init(ChunkHandle& ch, MeshTaskType cType, const BlockPack* blockPack, ChunkMeshManager* meshManager);\n\n    MeshTaskType type; \n    ChunkHandle chunk;\n    ChunkMeshManager* meshManager = nullptr;\n    const BlockPack* blockPack = nullptr;\n    ChunkHandle neighborHandles[NUM_NEIGHBOR_HANDLES];\nprivate:\n    void updateLight(VoxelLightEngine* voxelLightEngine);\n};\n\n#endif // RenderTask_h__\n"
  },
  {
    "path": "SoA/ChunkMesher.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkMesher.h\"\n\n#include <random>\n\n\n#include \"Biome.h\"\n#include \"BlockData.h\"\n\n#include <Vorb/ThreadPool.h>\n#include <Vorb/utils.h>\n\n#include \"BlockPack.h\"\n#include \"Chunk.h\"\n#include \"ChunkMeshTask.h\"\n#include \"ChunkRenderer.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"SoaOptions.h\"\n#include \"VoxelBits.h\"\n#include \"VoxelMesher.h\"\n#include \"VoxelUtils.h\"\n\n#define GETBLOCK(a) blocks->operator[](a)\n\n// const float LIGHT_MULT = 0.95f, LIGHT_OFFSET = -0.2f;\n\n// const int MAXLIGHT = 31;\n\n// Shorter aliases\n#define PADDED_WIDTH PADDED_CHUNK_WIDTH\n#define PADDED_LAYER PADDED_CHUNK_LAYER\n#define PADDED_SIZE PADDED_CHUNK_SIZE\nconst int PADDED_WIDTH_M1 = PADDED_WIDTH - 1;\n\n#define NO_QUAD_INDEX 0xFFFF\n\n#define QUAD_SIZE 7\n\n//#define USE_AO\n\n// Base texture index\n#define B_INDEX 0\n// Overlay texture index\n#define O_INDEX 1\n\nconst int X_NEG = (int)vvox::Cardinal::X_NEG;\nconst int X_POS = (int)vvox::Cardinal::X_POS;\nconst int Y_NEG = (int)vvox::Cardinal::Y_NEG;\nconst int Y_POS = (int)vvox::Cardinal::Y_POS;\nconst int Z_NEG = (int)vvox::Cardinal::Z_NEG;\nconst int Z_POS = (int)vvox::Cardinal::Z_POS;\n\n#define UV_0 128\n#define UV_1 129\n\n// Meshing constants\n//0 = x, 1 = y, 2 = z\nconst int FACE_AXIS[6][2] = { { 2, 1 }, { 2, 1 }, { 0, 2 }, { 0, 2 }, { 0, 1 }, { 0, 1 } };\n\nconst int FACE_AXIS_SIGN[6][2] = { { 1, 1 }, { -1, 1 }, { 1, 1 }, { -1, 1 }, { -1, 1 }, { 1, 1 } };\n\nPlanetHeightData ChunkMesher::defaultChunkHeightData[CHUNK_LAYER] = {};\n\nvoid ChunkMesher::init(const BlockPack* blocks) {\n    this->blocks = blocks;\n\n    // Set up the texture params\n    m_textureMethodParams[X_NEG][B_INDEX].init(this, PADDED_CHUNK_WIDTH, PADDED_CHUNK_LAYER, -1, X_NEG, B_INDEX);\n    m_textureMethodParams[X_NEG][O_INDEX].init(this, PADDED_CHUNK_WIDTH, PADDED_CHUNK_LAYER, -1, X_NEG, O_INDEX);\n\n    m_textureMethodParams[X_POS][B_INDEX].init(this, -PADDED_CHUNK_WIDTH, PADDED_CHUNK_LAYER, 1, X_POS, B_INDEX);\n    m_textureMethodParams[X_POS][O_INDEX].init(this, -PADDED_CHUNK_WIDTH, PADDED_CHUNK_LAYER, 1, X_POS, O_INDEX);\n\n    m_textureMethodParams[Y_NEG][B_INDEX].init(this, -1, -PADDED_CHUNK_WIDTH, -PADDED_CHUNK_LAYER, Y_NEG, B_INDEX);\n    m_textureMethodParams[Y_NEG][O_INDEX].init(this, -1, -PADDED_CHUNK_WIDTH, -PADDED_CHUNK_LAYER, Y_NEG, O_INDEX);\n\n    m_textureMethodParams[Y_POS][B_INDEX].init(this, 1, -PADDED_CHUNK_WIDTH, PADDED_CHUNK_LAYER, Y_POS, B_INDEX);\n    m_textureMethodParams[Y_POS][O_INDEX].init(this, 1, -PADDED_CHUNK_WIDTH, PADDED_CHUNK_LAYER, Y_POS, O_INDEX);\n\n    m_textureMethodParams[Z_NEG][B_INDEX].init(this, -1, PADDED_CHUNK_LAYER, -PADDED_CHUNK_WIDTH, Z_NEG, B_INDEX);\n    m_textureMethodParams[Z_NEG][O_INDEX].init(this, -1, PADDED_CHUNK_LAYER, -PADDED_CHUNK_WIDTH, Z_NEG, O_INDEX);\n\n    m_textureMethodParams[Z_POS][B_INDEX].init(this, 1, PADDED_CHUNK_LAYER, PADDED_CHUNK_WIDTH, Z_POS, B_INDEX);\n    m_textureMethodParams[Z_POS][O_INDEX].init(this, 1, PADDED_CHUNK_LAYER, PADDED_CHUNK_WIDTH, Z_POS, O_INDEX);\n}\n\nvoid ChunkMesher::prepareData(const Chunk* chunk) {\n    int x, y, z, off1, off2;\n\n    const Chunk* left = chunk->neighbor.left;\n    const Chunk* right = chunk->neighbor.right;\n    const Chunk* bottom = chunk->neighbor.bottom;\n    const Chunk* top = chunk->neighbor.top;\n    const Chunk* back = chunk->neighbor.back;\n    const Chunk* front = chunk->neighbor.front;\n    int wc;\n    int c = 0;\n\n    i32v3 pos;\n\n    wSize = 0;\n    chunkVoxelPos = chunk->getVoxelPosition();\n    if (chunk->gridData) {\n        m_chunkHeightData = chunk->gridData->heightData;\n    } else {\n        m_chunkHeightData = defaultChunkHeightData;\n    }\n\n    // TODO(Ben): Do this last so we can be queued for mesh longer?\n    // TODO(Ben): Dude macro this or something.\n\n    memset(blockData, 0, sizeof(blockData));\n    memset(tertiaryData, 0, sizeof(tertiaryData));\n \n    if (chunk->blocks.getState() == vvox::VoxelStorageState::INTERVAL_TREE) {\n\n        int s = 0;\n        //block data\n        auto& dataTree = chunk->blocks.getTree();\n        for (size_t i = 0; i < dataTree.size(); i++) {\n            for (size_t j = 0; j < dataTree[i].length; j++) {\n                c = dataTree[i].getStart() + j;\n\n                getPosFromBlockIndex(c, pos);\n\n                wc = (pos.y + 1)*PADDED_LAYER + (pos.z + 1)*PADDED_WIDTH + (pos.x + 1);\n                blockData[wc] = dataTree[i].data;\n                if (GETBLOCK(blockData[wc]).meshType == MeshType::LIQUID) {\n                    m_wvec[s++] = wc;\n                }\n\n            }\n        }\n        wSize = s;\n    } else {\n        int s = 0;\n        for (y = 0; y < CHUNK_WIDTH; y++) {\n            for (z = 0; z < CHUNK_WIDTH; z++) {\n                for (x = 0; x < CHUNK_WIDTH; x++, c++) {\n                    wc = (y + 1)*PADDED_LAYER + (z + 1)*PADDED_WIDTH + (x + 1);\n                    blockData[wc] = chunk->blocks[c];\n                    if (GETBLOCK(blockData[wc]).meshType == MeshType::LIQUID) {\n                        m_wvec[s++] = wc;\n                    }\n                }\n            }\n        }\n        wSize = s;\n    }\n    if (chunk->tertiary.getState() == vvox::VoxelStorageState::INTERVAL_TREE) {\n        //tertiary data\n        c = 0;\n        auto& dataTree = chunk->tertiary.getTree();\n        for (size_t i = 0; i < dataTree.size(); i++) {\n            for (size_t j = 0; j < dataTree[i].length; j++) {\n                c = dataTree[i].getStart() + j;\n\n                getPosFromBlockIndex(c, pos);\n                wc = (pos.y + 1)*PADDED_LAYER + (pos.z + 1)*PADDED_WIDTH + (pos.x + 1);\n\n                tertiaryData[wc] = dataTree[i].data;\n            }\n        }\n\n    } else {\n        c = 0;\n        for (y = 0; y < CHUNK_WIDTH; y++) {\n            for (z = 0; z < CHUNK_WIDTH; z++) {\n                for (x = 0; x < CHUNK_WIDTH; x++, c++) {\n                    wc = (y + 1)*PADDED_LAYER + (z + 1)*PADDED_WIDTH + (x + 1);\n                    tertiaryData[wc] = chunk->tertiary.get(c);\n                }\n            }\n        }\n    }\n\n    if (left) {\n        for (y = 1; y < PADDED_WIDTH - 1; y++) {\n            for (z = 1; z < PADDED_WIDTH - 1; z++) {\n                off1 = (z - 1)*CHUNK_WIDTH + (y - 1)*CHUNK_LAYER;\n                off2 = z*PADDED_WIDTH + y*PADDED_LAYER;\n\n                blockData[off2] = left->getBlockData(off1 + CHUNK_WIDTH - 1);\n                tertiaryData[off2] = left->getTertiaryData(off1 + CHUNK_WIDTH - 1);\n            }\n        }\n    }\n\n    if (right) {\n        for (y = 1; y < PADDED_WIDTH - 1; y++) {\n            for (z = 1; z < PADDED_WIDTH - 1; z++) {\n                off1 = (z - 1)*CHUNK_WIDTH + (y - 1)*CHUNK_LAYER;\n                off2 = z*PADDED_WIDTH + y*PADDED_LAYER;\n\n                blockData[off2 + PADDED_WIDTH - 1] = (right->getBlockData(off1));\n                tertiaryData[off2 + PADDED_WIDTH - 1] = right->getTertiaryData(off1);\n            }\n        }\n    }\n\n    if (bottom) {\n        for (z = 1; z < PADDED_WIDTH - 1; z++) {\n            for (x = 1; x < PADDED_WIDTH - 1; x++) {\n                off1 = (z - 1)*CHUNK_WIDTH + x - 1;\n                off2 = z*PADDED_WIDTH + x;\n                //data\n                blockData[off2] = (bottom->getBlockData(CHUNK_SIZE - CHUNK_LAYER + off1)); //bottom\n                tertiaryData[off2] = bottom->getTertiaryData(CHUNK_SIZE - CHUNK_LAYER + off1);\n            }\n        }\n    }\n\n    if (top) {\n        for (z = 1; z < PADDED_WIDTH - 1; z++) {\n            for (x = 1; x < PADDED_WIDTH - 1; x++) {\n                off1 = (z - 1)*CHUNK_WIDTH + x - 1;\n                off2 = z*PADDED_WIDTH + x;\n\n                blockData[off2 + PADDED_SIZE - PADDED_LAYER] = (top->getBlockData(off1)); //top\n                tertiaryData[off2 + PADDED_SIZE - PADDED_LAYER] = top->getTertiaryData(off1);\n            }\n        }\n    }\n\n    if (back) {\n        for (y = 1; y < PADDED_WIDTH - 1; y++) {\n            for (x = 1; x < PADDED_WIDTH - 1; x++) {\n                off1 = (x - 1) + (y - 1)*CHUNK_LAYER;\n                off2 = x + y*PADDED_LAYER;\n\n                blockData[off2] = back->getBlockData(off1 + CHUNK_LAYER - CHUNK_WIDTH);\n                tertiaryData[off2] = back->getTertiaryData(off1 + CHUNK_LAYER - CHUNK_WIDTH);\n            }\n        }\n    }\n\n    if (front) {\n        for (y = 1; y < PADDED_WIDTH - 1; y++) {\n            for (x = 1; x < PADDED_WIDTH - 1; x++) {\n                off1 = (x - 1) + (y - 1)*CHUNK_LAYER;\n                off2 = x + y*PADDED_LAYER;\n\n                blockData[off2 + PADDED_LAYER - PADDED_WIDTH] = (front->getBlockData(off1));\n                tertiaryData[off2 + PADDED_LAYER - PADDED_WIDTH] = front->getTertiaryData(off1);\n            }\n        }\n    }\n}\n\n#define GET_EDGE_X(ch, sy, sz, dy, dz) \\\n    { \\\n      std::lock_guard<std::mutex> l(ch->dataMutex); \\\n      for (int x = 0; x < CHUNK_WIDTH; x++) { \\\n          srcIndex = (sy) * CHUNK_LAYER + (sz) * CHUNK_WIDTH + x; \\\n          destIndex = (dy) * PADDED_LAYER + (dz) * PADDED_WIDTH + (x + 1); \\\n          blockData[destIndex] = ch->getBlockData(srcIndex); \\\n          tertiaryData[destIndex] = ch->getTertiaryData(srcIndex); \\\n      } \\\n    } \\\n    ch.release();\n\n#define GET_EDGE_Y(ch, sx, sz, dx, dz) \\\n    { \\\n      std::lock_guard<std::mutex> l(ch->dataMutex); \\\n      for (int y = 0; y < CHUNK_WIDTH; y++) { \\\n        srcIndex = y * CHUNK_LAYER + (sz) * CHUNK_WIDTH + (sx); \\\n        destIndex = (y + 1) * PADDED_LAYER + (dz) * PADDED_WIDTH + (dx); \\\n        blockData[destIndex] = ch->getBlockData(srcIndex); \\\n        tertiaryData[destIndex] = ch->getTertiaryData(srcIndex); \\\n      } \\\n    } \\\n    ch.release();\n\n#define GET_EDGE_Z(ch, sx, sy, dx, dy) \\\n    { \\\n      std::lock_guard<std::mutex> l(ch->dataMutex); \\\n      for (int z = 0; z < CHUNK_WIDTH; z++) { \\\n        srcIndex = z * CHUNK_WIDTH + (sy) * CHUNK_LAYER + (sx); \\\n        destIndex = (z + 1) * PADDED_WIDTH + (dy) * PADDED_LAYER + (dx); \\\n        blockData[destIndex] = ch->getBlockData(srcIndex); \\\n        tertiaryData[destIndex] = ch->getTertiaryData(srcIndex); \\\n      } \\\n    } \\\n    ch.release();\n\n#define GET_CORNER(ch, sx, sy, sz, dx, dy, dz) \\\n    srcIndex = (sy) * CHUNK_LAYER + (sz) * CHUNK_WIDTH + (sx); \\\n    destIndex = (dy) * PADDED_LAYER + (dz) * PADDED_WIDTH + (dx); \\\n    { \\\n      std::lock_guard<std::mutex> l(ch->dataMutex); \\\n      blockData[destIndex] = ch->getBlockData(srcIndex); \\\n      tertiaryData[destIndex] = ch->getTertiaryData(srcIndex); \\\n    } \\\n    ch.release();\n\nvoid ChunkMesher::prepareDataAsync(ChunkHandle& chunk, ChunkHandle neighbors[NUM_NEIGHBOR_HANDLES]) {\n    int x, y, z, srcIndex, destIndex;\n\n    int wc;\n    int c = 0;\n\n    i32v3 pos;\n\n    wSize = 0;\n    chunkVoxelPos = chunk->getVoxelPosition();\n    if (chunk->gridData) {\n        // If its async we copy to avoid storing a shared_ptr\n        memcpy(heightDataBuffer, chunk->gridData->heightData, sizeof(heightDataBuffer));\n        m_chunkHeightData = heightDataBuffer;\n    } else {\n        m_chunkHeightData = defaultChunkHeightData;\n    }\n\n    // TODO(Ben): Do this last so we can be queued for mesh longer?\n    // TODO(Ben): Dude macro this or something.\n    { // Main chunk\n        std::lock_guard<std::mutex> l(chunk->dataMutex);\n        if (chunk->blocks.getState() == vvox::VoxelStorageState::INTERVAL_TREE) {\n\n            int s = 0;\n            //block data\n            auto& dataTree = chunk->blocks.getTree();\n            for (size_t i = 0; i < dataTree.size(); i++) {\n                for (size_t j = 0; j < dataTree[i].length; j++) {\n                    c = dataTree[i].getStart() + j;\n\n                    getPosFromBlockIndex(c, pos);\n\n                    wc = (pos.y + 1)*PADDED_LAYER + (pos.z + 1)*PADDED_WIDTH + (pos.x + 1);\n                    blockData[wc] = dataTree[i].data;\n                    if (GETBLOCK(blockData[wc]).meshType == MeshType::LIQUID) {\n                        m_wvec[s++] = wc;\n                    }\n                }\n            }\n            wSize = s;\n        } else {\n            int s = 0;\n            for (y = 0; y < CHUNK_WIDTH; y++) {\n                for (z = 0; z < CHUNK_WIDTH; z++) {\n                    for (x = 0; x < CHUNK_WIDTH; x++, c++) {\n                        wc = (y + 1)*PADDED_LAYER + (z + 1)*PADDED_WIDTH + (x + 1);\n                        blockData[wc] = chunk->blocks[c];\n                        if (GETBLOCK(blockData[wc]).meshType == MeshType::LIQUID) {\n                            m_wvec[s++] = wc;\n                        }\n                    }\n                }\n            }\n            wSize = s;\n        }\n        if (chunk->tertiary.getState() == vvox::VoxelStorageState::INTERVAL_TREE) {\n            //tertiary data\n            c = 0;\n            auto& dataTree = chunk->tertiary.getTree();\n            for (size_t i = 0; i < dataTree.size(); i++) {\n                for (size_t j = 0; j < dataTree[i].length; j++) {\n                    c = dataTree[i].getStart() + j;\n\n                    getPosFromBlockIndex(c, pos);\n                    wc = (pos.y + 1)*PADDED_LAYER + (pos.z + 1)*PADDED_WIDTH + (pos.x + 1);\n\n                    tertiaryData[wc] = dataTree[i].data;\n                }\n            }\n\n        } else {\n            c = 0;\n            for (y = 0; y < CHUNK_WIDTH; y++) {\n                for (z = 0; z < CHUNK_WIDTH; z++) {\n                    for (x = 0; x < CHUNK_WIDTH; x++, c++) {\n                        wc = (y + 1)*PADDED_LAYER + (z + 1)*PADDED_WIDTH + (x + 1);\n                        tertiaryData[wc] = chunk->tertiary.get(c);\n                    }\n                }\n            }\n        }\n    }\n    chunk.release();\n\n    ChunkHandle& left = neighbors[NEIGHBOR_HANDLE_LEFT];\n    { // Left\n        std::lock_guard<std::mutex> l(left->dataMutex);\n        for (y = 1; y < PADDED_WIDTH - 1; y++) {\n            for (z = 1; z < PADDED_WIDTH - 1; z++) {\n                srcIndex = (z - 1)*CHUNK_WIDTH + (y - 1)*CHUNK_LAYER;\n                destIndex = z*PADDED_WIDTH + y*PADDED_LAYER;\n\n                blockData[destIndex] = left->getBlockData(srcIndex + CHUNK_WIDTH - 1);\n                tertiaryData[destIndex] = left->getTertiaryData(srcIndex + CHUNK_WIDTH - 1);\n            }\n        }\n    }\n    left.release();\n\n    ChunkHandle& right = neighbors[NEIGHBOR_HANDLE_RIGHT];\n    { // Right\n        std::lock_guard<std::mutex> l(right->dataMutex);\n        for (y = 1; y < PADDED_WIDTH - 1; y++) {\n            for (z = 1; z < PADDED_WIDTH - 1; z++) {\n                srcIndex = (z - 1)*CHUNK_WIDTH + (y - 1)*CHUNK_LAYER;\n                destIndex = z*PADDED_WIDTH + y*PADDED_LAYER + PADDED_WIDTH - 1;\n\n                blockData[destIndex] = (right->getBlockData(srcIndex));\n                tertiaryData[destIndex] = right->getTertiaryData(srcIndex);\n            }\n        }\n    }\n    right.release();\n\n    ChunkHandle& bottom = neighbors[NEIGHBOR_HANDLE_BOT];\n    { // Bottom\n        std::lock_guard<std::mutex> l(bottom->dataMutex);\n        for (z = 1; z < PADDED_WIDTH - 1; z++) {\n            for (x = 1; x < PADDED_WIDTH - 1; x++) {\n                srcIndex = (z - 1)*CHUNK_WIDTH + x - 1 + CHUNK_SIZE - CHUNK_LAYER;\n                destIndex = z*PADDED_WIDTH + x;\n                //data\n                blockData[destIndex] = (bottom->getBlockData(srcIndex)); //bottom\n                tertiaryData[destIndex] = bottom->getTertiaryData(srcIndex);\n            }\n        }\n    }\n    bottom.release();\n\n    ChunkHandle& top = neighbors[NEIGHBOR_HANDLE_TOP];\n    { // Top\n        std::lock_guard<std::mutex> l(top->dataMutex);\n        for (z = 1; z < PADDED_WIDTH - 1; z++) {\n            for (x = 1; x < PADDED_WIDTH - 1; x++) {\n                srcIndex = (z - 1)*CHUNK_WIDTH + x - 1;\n                destIndex = z*PADDED_WIDTH + x + PADDED_SIZE - PADDED_LAYER;\n\n                blockData[destIndex] = (top->getBlockData(srcIndex)); //top\n                tertiaryData[destIndex] = top->getTertiaryData(srcIndex);\n            }\n        }\n    }\n    top.release();\n\n    ChunkHandle& back = neighbors[NEIGHBOR_HANDLE_BACK];\n    { // Back\n        std::lock_guard<std::mutex> l(back->dataMutex);\n        for (y = 1; y < PADDED_WIDTH - 1; y++) {\n            for (x = 1; x < PADDED_WIDTH - 1; x++) {\n                srcIndex = (x - 1) + (y - 1)*CHUNK_LAYER + CHUNK_LAYER - CHUNK_WIDTH;\n                destIndex = x + y*PADDED_LAYER;\n\n                blockData[destIndex] = back->getBlockData(srcIndex);\n                tertiaryData[destIndex] = back->getTertiaryData(srcIndex);\n            }\n        }\n    }\n    back.release();\n\n    ChunkHandle& front = neighbors[NEIGHBOR_HANDLE_FRONT];\n    { // Front\n        std::lock_guard<std::mutex> l(front->dataMutex);\n        for (y = 1; y < PADDED_WIDTH - 1; y++) {\n            for (x = 1; x < PADDED_WIDTH - 1; x++) {\n                srcIndex = (x - 1) + (y - 1)*CHUNK_LAYER;\n                destIndex = x + y*PADDED_LAYER + PADDED_LAYER - PADDED_WIDTH;\n\n                blockData[destIndex] = front->getBlockData(srcIndex);\n                tertiaryData[destIndex] = front->getTertiaryData(srcIndex);\n            }\n        }\n    }\n    front.release();\n    // Clone edge data\n    // TODO(Ben): Light gradient calc\n    // X horizontal rows\n    for (x = 1; x < PADDED_WIDTH_M1; x++) {\n        // Bottom Back\n        srcIndex = x + PADDED_WIDTH;\n        destIndex = x;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Bottom Front\n        srcIndex = x + PADDED_LAYER - PADDED_WIDTH * 2;\n        destIndex = srcIndex + PADDED_WIDTH;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Top Back\n        srcIndex = x + PADDED_WIDTH + PADDED_SIZE - PADDED_LAYER;\n        destIndex = srcIndex - PADDED_WIDTH;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Top Front\n        srcIndex = x + PADDED_SIZE - PADDED_WIDTH * 2;\n        destIndex = srcIndex + PADDED_WIDTH;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n    }\n    // Z horizontal rows\n    for (z = 1; z < PADDED_WIDTH_M1; z++) {\n        int zi = z * PADDED_WIDTH;\n        // Bottom Left\n        srcIndex = zi + 1;\n        destIndex = zi;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Bottom Right\n        srcIndex = zi + PADDED_WIDTH - 2;\n        destIndex = srcIndex + 1;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Top Left\n        srcIndex = zi + PADDED_SIZE - PADDED_LAYER + 1;\n        destIndex = srcIndex - 1;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Top Right\n        srcIndex = zi + PADDED_SIZE - PADDED_LAYER + PADDED_WIDTH - 2;\n        destIndex = srcIndex + 1;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n    }\n    // Vertical columns\n    for (y = 0; y < PADDED_WIDTH; y++) {\n        int yi = y * PADDED_LAYER;\n        // Left back\n        srcIndex = yi + 1;\n        destIndex = yi;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Left front\n        srcIndex = yi + PADDED_LAYER - PADDED_WIDTH + 1;\n        destIndex = srcIndex - 1;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Right back\n        srcIndex = yi + PADDED_WIDTH - 2;\n        destIndex = srcIndex + 1;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n        // Right front\n        srcIndex = yi + PADDED_LAYER - 2;\n        destIndex = srcIndex + 1;\n        blockData[destIndex] = blockData[srcIndex];\n        tertiaryData[destIndex] = tertiaryData[srcIndex];\n    }\n}\n\nCALLER_DELETE ChunkMeshData* ChunkMesher::createChunkMeshData(MeshTaskType type VORB_UNUSED) {\n    m_numQuads = 0;\n    m_highestY = 0;\n    m_lowestY = 256;\n    m_highestX = 0;\n    m_lowestX = 256;\n    m_highestZ = 0;\n    m_lowestZ = 256;\n\n    // Clear quad indices\n    memset(m_quadIndices, 0xFF, sizeof(m_quadIndices));\n\n    for (int i = 0; i < 6; i++) {\n        m_quads[i].clear();\n    }\n\n    // TODO(Ben): Here?\n    _waterVboVerts.clear();\n\n    // Stores the data for a chunk mesh\n    // TODO(Ben): new is bad mkay\n    m_chunkMeshData = new ChunkMeshData(MeshTaskType::DEFAULT);\n\n    // Loop through blocks\n    for (by = 0; by < CHUNK_WIDTH; by++) {\n        for (bz = 0; bz < CHUNK_WIDTH; bz++) {\n            for (bx = 0; bx < CHUNK_WIDTH; bx++) {\n                // Get data for this voxel\n                // TODO(Ben): Could optimize out -1\n                blockIndex = (by + 1) * PADDED_CHUNK_LAYER + (bz + 1) * PADDED_CHUNK_WIDTH + (bx + 1);\n                blockID = blockData[blockIndex];\n                if (blockID == 0) continue; // Skip air blocks\n                heightData = &m_chunkHeightData[bz * CHUNK_WIDTH + bx];\n                block = &blocks->operator[](blockID);\n                // TODO(Ben) Don't think bx needs to be member\n                voxelPosOffset = ui8v3(bx * QUAD_SIZE, by * QUAD_SIZE, bz * QUAD_SIZE);\n\n                switch (block->meshType) {\n                    case MeshType::BLOCK:\n                        addBlock();\n                        break;\n                    case MeshType::LEAVES:\n                    case MeshType::CROSSFLORA:\n                    case MeshType::TRIANGLE:\n                        addFlora();\n                        break;\n                    default:\n                        //No mesh, do nothing\n                        break;\n                }\n            }\n        }\n    }\n\n    ChunkMeshRenderData& renderData = m_chunkMeshData->chunkMeshRenderData;\n\n    // Get quad buffer to fill\n    std::vector<VoxelQuad>& finalQuads = m_chunkMeshData->opaqueQuads;\n\n    finalQuads.resize(m_numQuads);\n    // Copy the data\n    // TODO(Ben): Could construct in place and not need ANY copying with 6 iterations?\n    i32 index = 0;\n    i32 sizes[6];\n    for (int i = 0; i < 6; i++) {\n        std::vector<VoxelQuad>& quads = m_quads[i];\n        int tmp = index;\n        for (size_t j = 0; j < quads.size(); j++) {\n            VoxelQuad& q = quads[j];\n            if (q.v.v0.mesherFlags & MESH_FLAG_ACTIVE) {\n                finalQuads[index++] = q;\n            }\n        }\n        sizes[i] = index - tmp;\n    }\n\n    // Swap flora quads\n    renderData.cutoutVboSize = m_floraQuads.size() * INDICES_PER_QUAD;\n    m_chunkMeshData->cutoutQuads.swap(m_floraQuads);\n\n    m_highestY /= QUAD_SIZE;\n    m_lowestY /= QUAD_SIZE;\n    m_highestX /= QUAD_SIZE;\n    m_lowestX /= QUAD_SIZE;\n    m_highestZ /= QUAD_SIZE;\n    m_lowestZ /= QUAD_SIZE;\n\n#define INDICES_PER_QUAD 6\n\n    if (finalQuads.size()) {\n        renderData.nxVboOff = 0;\n        renderData.nxVboSize = sizes[0] * INDICES_PER_QUAD;\n        renderData.pxVboOff = renderData.nxVboSize;\n        renderData.pxVboSize = sizes[1] * INDICES_PER_QUAD;\n        renderData.nyVboOff = renderData.pxVboOff + renderData.pxVboSize;\n        renderData.nyVboSize = sizes[2] * INDICES_PER_QUAD;\n        renderData.pyVboOff = renderData.nyVboOff + renderData.nyVboSize;\n        renderData.pyVboSize = sizes[3] * INDICES_PER_QUAD;\n        renderData.nzVboOff = renderData.pyVboOff + renderData.pyVboSize;\n        renderData.nzVboSize = sizes[4] * INDICES_PER_QUAD;\n        renderData.pzVboOff = renderData.nzVboOff + renderData.nzVboSize;\n        renderData.pzVboSize = sizes[5] * INDICES_PER_QUAD;\n        renderData.indexSize = finalQuads.size() * INDICES_PER_QUAD;\n\n        // Redundant\n        renderData.highestX = m_highestX;\n        renderData.lowestX = m_lowestX;\n        renderData.highestY = m_highestY;\n        renderData.lowestY = m_lowestY;\n        renderData.highestZ = m_highestZ;\n        renderData.lowestZ = m_lowestZ;\n    }\n\n    return m_chunkMeshData;\n}\n\ninline bool mapBufferData(GLuint& vboID, GLsizeiptr size, void* src, GLenum usage) {\n    // Block Vertices\n    if (vboID == 0) {\n        glGenBuffers(1, &(vboID)); // Create the buffer ID\n    }\n    glBindBuffer(GL_ARRAY_BUFFER, vboID);\n    glBufferData(GL_ARRAY_BUFFER, size, NULL, usage);\n\n    void *v = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);\n\n    if (v == NULL) return false;\n\n    memcpy(v, src, size);\n    glUnmapBuffer(GL_ARRAY_BUFFER);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    return true;\n}\n\nbool ChunkMesher::uploadMeshData(ChunkMesh& mesh, ChunkMeshData* meshData) {\n    bool canRender = false;\n\n    //store the index data for sorting in the chunk mesh\n    mesh.transQuadIndices.swap(meshData->transQuadIndices);\n    mesh.transQuadPositions.swap(meshData->transQuadPositions);\n\n    switch (meshData->type) {\n        case MeshTaskType::DEFAULT:\n            if (meshData->opaqueQuads.size()) {\n\n                mapBufferData(mesh.vboID, meshData->opaqueQuads.size() * sizeof(VoxelQuad), &(meshData->opaqueQuads[0]), GL_STATIC_DRAW);\n                canRender = true;\n\n                if (!mesh.vaoID) buildVao(mesh);\n            } else {\n                if (mesh.vboID != 0) {\n                    glDeleteBuffers(1, &(mesh.vboID));\n                    mesh.vboID = 0;\n                }\n                if (mesh.vaoID != 0) {\n                    glDeleteVertexArrays(1, &(mesh.vaoID));\n                    mesh.vaoID = 0;\n                }\n            }\n\n            if (meshData->transQuads.size()) {\n\n                //vertex data\n                mapBufferData(mesh.transVboID, meshData->transQuads.size() * sizeof(VoxelQuad), &(meshData->transQuads[0]), GL_STATIC_DRAW);\n\n                //index data\n                mapBufferData(mesh.transIndexID, mesh.transQuadIndices.size() * sizeof(ui32), &(mesh.transQuadIndices[0]), GL_STATIC_DRAW);\n                canRender = true;\n                mesh.needsSort = true; //must sort when changing the mesh\n\n                if (!mesh.transVaoID) buildTransparentVao(mesh);\n            } else {\n                if (mesh.transVaoID != 0) {\n                    glDeleteVertexArrays(1, &(mesh.transVaoID));\n                    mesh.transVaoID = 0;\n                }\n                if (mesh.transVboID != 0) {\n                    glDeleteBuffers(1, &(mesh.transVboID));\n                    mesh.transVboID = 0;\n                }\n                if (mesh.transIndexID != 0) {\n                    glDeleteBuffers(1, &(mesh.transIndexID));\n                    mesh.transIndexID = 0;\n                }\n            }\n\n            if (meshData->cutoutQuads.size()) {\n\n                mapBufferData(mesh.cutoutVboID, meshData->cutoutQuads.size() * sizeof(VoxelQuad), &(meshData->cutoutQuads[0]), GL_STATIC_DRAW);\n                canRender = true;\n                if (!mesh.cutoutVaoID) buildCutoutVao(mesh);\n            } else {\n                if (mesh.cutoutVaoID != 0) {\n                    glDeleteVertexArrays(1, &(mesh.cutoutVaoID));\n                    mesh.cutoutVaoID = 0;\n                }\n                if (mesh.cutoutVboID != 0) {\n                    glDeleteBuffers(1, &(mesh.cutoutVboID));\n                    mesh.cutoutVboID = 0;\n                }\n            }\n            mesh.renderData = meshData->chunkMeshRenderData;\n            //The missing break is deliberate!\n            VORB_FALLTHROUGH;\n        case MeshTaskType::LIQUID:\n\n            mesh.renderData.waterIndexSize = meshData->chunkMeshRenderData.waterIndexSize;\n            if (meshData->waterVertices.size()) {\n                mapBufferData(mesh.waterVboID, meshData->waterVertices.size() * sizeof(LiquidVertex), &(meshData->waterVertices[0]), GL_STREAM_DRAW);\n                canRender = true;\n                if (!mesh.waterVaoID) buildWaterVao(mesh);\n            } else {\n                if (mesh.waterVboID != 0) {\n                    glDeleteBuffers(1, &(mesh.waterVboID));\n                    mesh.waterVboID = 0;\n                }\n                if (mesh.waterVaoID != 0) {\n                    glDeleteVertexArrays(1, &(mesh.waterVaoID));\n                    mesh.waterVaoID = 0;\n                }\n            }\n            break;\n    }\n    return canRender;\n}\n\nvoid ChunkMesher::freeChunkMesh(CALLEE_DELETE ChunkMesh* mesh) {\n    // Opaque\n    if (mesh->vboID != 0) {\n        glDeleteBuffers(1, &mesh->vboID);\n    }\n    if (mesh->vaoID != 0) {\n        glDeleteVertexArrays(1, &mesh->vaoID);\n    }\n    // Transparent\n    if (mesh->transVaoID != 0) {\n        glDeleteVertexArrays(1, &mesh->transVaoID);\n    }\n    if (mesh->transVboID != 0) {\n        glDeleteBuffers(1, &mesh->transVboID);\n    }\n    if (mesh->transIndexID != 0) {\n        glDeleteBuffers(1, &mesh->transIndexID);\n    }\n    // Cutout\n    if (mesh->cutoutVaoID != 0) {\n        glDeleteVertexArrays(1, &mesh->cutoutVaoID);\n    }\n    if (mesh->cutoutVboID != 0) {\n        glDeleteBuffers(1, &mesh->cutoutVboID);\n    }\n    // Liquid\n    if (mesh->waterVboID != 0) {\n        glDeleteBuffers(1, &mesh->waterVboID);\n    }\n    if (mesh->waterVaoID != 0) {\n        glDeleteVertexArrays(1, &mesh->waterVaoID);\n    }\n    delete mesh;\n}\n//\n//CALLEE_DELETE ChunkMeshData* ChunkMesher::createOnlyWaterMesh(const Chunk* chunk) {\n//    /*if (chunkMeshData != NULL) {\n//        pError(\"Tried to create mesh with in use chunkMeshData!\");\n//        return 0;\n//        }\n//        chunkMeshData = new ChunkMeshData(renderTask);\n//\n//        _waterVboVerts.clear();\n//\n//        mi.task = renderTask;\n//\n//        for (int i = 0; i < wSize; i++) {\n//        mi.wc = m_wvec[i];\n//        mi.btype = GETBLOCKID(blockData[mi.wc]);\n//        mi.x = (mi.wc % PADDED_CHUNK_WIDTH) - 1;\n//        mi.y = (mi.wc / PADDED_CHUNK_LAYER) - 1;\n//        mi.z = ((mi.wc % PADDED_CHUNK_LAYER) / PADDED_CHUNK_WIDTH) - 1;\n//\n//        addLiquid(mi);\n//        }\n//\n//\n//        if (mi.liquidIndex) {\n//        chunkMeshData->chunkMeshRenderData.waterIndexSize = (mi.liquidIndex * 6) / 4;\n//        chunkMeshData->waterVertices.swap(_waterVboVerts);\n//        }*/\n//\n//    return nullptr;\n//}\n\nvoid ChunkMesher::freeBuffers() {\n    //free memory\n    //std::vector <BlockVertex>().swap(_vboVerts);\n\n    //These dont get too big so it might be ok to not free them?\n    /*vector <Vertex>().swap(waterVboVerts);\n    vector<Vertex>().swap(finalTopVerts);\n    vector<Vertex>().swap(finalLeftVerts);\n    vector<Vertex>().swap(finalRightVerts);\n    vector<Vertex>().swap(finalFrontVerts);\n    vector<Vertex>().swap(finalBackVerts);\n    vector<Vertex>().swap(finalBottomVerts);\n    vector<Vertex>().swap(finalNbVerts);*/\n}\n\n#define CompareVertices(v1, v2) (!memcmp(&v1.color, &v2.color, 3) && v1.sunlight == v2.sunlight && !memcmp(&v1.lampColor, &v2.lampColor, 3)  \\\n    && !memcmp(&v1.overlayColor, &v2.overlayColor, 3) \\\n    && v1.textureAtlas == v2.textureAtlas && v1.textureIndex == v2.textureIndex && v1.overlayTextureAtlas == v2.overlayTextureAtlas && v1.overlayTextureIndex == v2.overlayTextureIndex)\n\n#define CompareVerticesLight(v1, v2) (v1.sunlight == v2.sunlight && !memcmp(&v1.lampColor, &v2.lampColor, 3) && !memcmp(&v1.color, &v2.color, 3))\n\nvoid ChunkMesher::addBlock()\n{\n    // Ambient occlusion buffer for vertices\n    f32 ao[4];\n\n    // Check the faces\n    // Left\n    if (shouldRenderFace(-1)) {\n        computeAmbientOcclusion(-1, -PADDED_CHUNK_LAYER, PADDED_CHUNK_WIDTH, ao);\n        addQuad(X_NEG, (int)vvox::Axis::Z, (int)vvox::Axis::Y, -PADDED_CHUNK_WIDTH, -PADDED_CHUNK_LAYER, 2, ui8v2(1, 1), ao);\n    }\n    // Right\n    if (shouldRenderFace(1)) {\n        computeAmbientOcclusion(1, -PADDED_CHUNK_LAYER, -PADDED_CHUNK_WIDTH, ao);\n        addQuad(X_POS, (int)vvox::Axis::Z, (int)vvox::Axis::Y, -PADDED_CHUNK_WIDTH, -PADDED_CHUNK_LAYER, 0, ui8v2(-1, 1), ao);\n    }\n    // Bottom\n    if (shouldRenderFace(-PADDED_CHUNK_LAYER)) { \n        computeAmbientOcclusion(-PADDED_CHUNK_LAYER, PADDED_CHUNK_WIDTH, 1, ao);\n        addQuad(Y_NEG, (int)vvox::Axis::X, (int)vvox::Axis::Z, -1, -PADDED_CHUNK_WIDTH, 2, ui8v2(1, 1), ao);\n    }\n    // Top\n    if (shouldRenderFace(PADDED_CHUNK_LAYER)) {\n        computeAmbientOcclusion(PADDED_CHUNK_LAYER, -PADDED_CHUNK_WIDTH, -1, ao);\n        addQuad(Y_POS, (int)vvox::Axis::X, (int)vvox::Axis::Z, -1, -PADDED_CHUNK_WIDTH, 0, ui8v2(-1, 1), ao);\n    }\n    // Back\n    if (shouldRenderFace(-PADDED_CHUNK_WIDTH)) {\n        computeAmbientOcclusion(-PADDED_CHUNK_WIDTH, -PADDED_CHUNK_LAYER, -1, ao);\n        addQuad(Z_NEG, (int)vvox::Axis::X, (int)vvox::Axis::Y, -1, -PADDED_CHUNK_LAYER, 0, ui8v2(-1, 1), ao);\n    }\n    // Front\n    if (shouldRenderFace(PADDED_CHUNK_WIDTH)) {\n        computeAmbientOcclusion(PADDED_CHUNK_WIDTH, -PADDED_CHUNK_LAYER, 1, ao);\n        addQuad(Z_POS, (int)vvox::Axis::X, (int)vvox::Axis::Y, -1, -PADDED_CHUNK_LAYER, 2, ui8v2(1, 1), ao);\n    }\n}\n\nvoid ChunkMesher::computeAmbientOcclusion(int upOffset VORB_UNUSED, int frontOffset VORB_UNUSED, int rightOffset VORB_UNUSED, f32 ambientOcclusion VORB_UNUSED[]) {\n#ifdef USE_AO\n    // Ambient occlusion factor\n#define OCCLUSION_FACTOR 0.2f;\n    // Helper macro\n    // TODO(Ben): This isn't exactly right since self will occlude. Use a function\n#define CALCULATE_VERTEX(v, s1, s2) \\\n    nearOccluders = getOcclusion(blocks->operator[](blockData[blockIndex])) + \\\n    getOcclusion(blocks->operator[](blockData[blockIndex s1 frontOffset])) + \\\n    getOcclusion(blocks->operator[](blockData[blockIndex s2 rightOffset])) + \\\n    getOcclusion(blocks->operator[](blockData[blockIndex s1 frontOffset s2 rightOffset])); \\\n    ambientOcclusion[v] = 1.0f - nearOccluders * OCCLUSION_FACTOR; \n   \n    // Move the block index upwards\n    int blockIndex = this->blockIndex + upOffset;\n    int nearOccluders; ///< For ambient occlusion\n\n    // TODO(Ben): I know for a fact the inputs are wrong for some faces\n\n    // Vertex 0\n    CALCULATE_VERTEX(0, -, -)\n\n    // Vertex 1\n    CALCULATE_VERTEX(1, +, -)\n\n    // Vertex 2\n    CALCULATE_VERTEX(2, +, +)\n\n    // Vertex 3\n    CALCULATE_VERTEX(3, -, +)\n#endif\n}\n\nvoid ChunkMesher::addQuad(int face, int rightAxis, int frontAxis, int leftOffset, int backOffset, int rightStretchIndex, const ui8v2& texOffset, f32 ambientOcclusion VORB_UNUSED[]) {\n    // Get texture TODO(Ben): Null check?\n    const BlockTexture* texture = block->textures[face];\n\n    // Get colors\n    // TODO(Ben): altColors\n    color3 blockColor[2];\n    texture->layers.base.getFinalColor(blockColor[B_INDEX],\n                                heightData->temperature,\n                                heightData->humidity, 0);\n    texture->layers.base.getFinalColor(blockColor[O_INDEX],\n                                heightData->temperature,\n                                heightData->humidity, 0);\n\n    std::vector<VoxelQuad>& quads = m_quads[face];\n\n    // Get texturing parameters\n    ui8 blendMode = getBlendMode(texture->blendMode);\n    // TODO(Ben): Make this better\n    BlockTextureMethodData methodDatas[6];\n    texture->layers.base.getBlockTextureMethodData(m_textureMethodParams[face][B_INDEX], blockColor[B_INDEX], methodDatas[0]);\n    texture->layers.base.getNormalTextureMethodData(m_textureMethodParams[face][B_INDEX], blockColor[B_INDEX], methodDatas[1]);\n    texture->layers.base.getDispTextureMethodData(m_textureMethodParams[face][B_INDEX], blockColor[B_INDEX], methodDatas[2]);\n    texture->layers.overlay.getBlockTextureMethodData(m_textureMethodParams[face][O_INDEX], blockColor[O_INDEX], methodDatas[3]);\n    texture->layers.overlay.getNormalTextureMethodData(m_textureMethodParams[face][O_INDEX], blockColor[O_INDEX], methodDatas[4]);\n    texture->layers.overlay.getDispTextureMethodData(m_textureMethodParams[face][O_INDEX], blockColor[O_INDEX], methodDatas[5]);\n\n    ui8 atlasIndices[6];\n    for (int i = 0; i < 6; i++) {\n        atlasIndices[i] = (ui8)(methodDatas[i].index / ATLAS_SIZE);\n        methodDatas[i].index &= ATLAS_MODULUS_BITS;\n    }\n    \n    i32v3 pos(bx, by, bz);\n    ui8 uOffset = (ui8)(pos[FACE_AXIS[face][0]] * FACE_AXIS_SIGN[face][0]);\n    ui8 vOffset = (ui8)(pos[FACE_AXIS[face][1]] * FACE_AXIS_SIGN[face][1]);\n\n    // Construct the quad\n    // i16 quadIndex = quads.size();\n    quads.emplace_back();\n    m_numQuads++;\n    VoxelQuad* quad = &quads.back();\n    quad->v.v0.mesherFlags = MESH_FLAG_ACTIVE;\n\n    for (int i = 0; i < 4; i++) {\n        BlockVertex& v = quad->verts[i];\n        v.position = VoxelMesher::VOXEL_POSITIONS[face][i] + voxelPosOffset;\n#ifdef USE_AO\n        f32& ao = ambientOcclusion[i];\n        v.color.r = (ui8)(blockColor[B_INDEX].r * ao);\n        v.color.g = (ui8)(blockColor[B_INDEX].g * ao);\n        v.color.b = (ui8)(blockColor[B_INDEX].b * ao);\n        v.overlayColor.r = (ui8)(blockColor[O_INDEX].r * ao);\n        v.overlayColor.g = (ui8)(blockColor[O_INDEX].g * ao);\n        v.overlayColor.b = (ui8)(blockColor[O_INDEX].b * ao);\n#else\n        v.color = blockColor[B_INDEX];\n        v.overlayColor = blockColor[O_INDEX];\n#endif\n        // TODO(Ben) array?\n        v.texturePosition.base.index = (ui8)methodDatas[0].index;\n        v.texturePosition.base.atlas = atlasIndices[0];\n        v.normTexturePosition.base.index = (ui8)methodDatas[1].index;\n        v.normTexturePosition.base.atlas = atlasIndices[1];\n        v.dispTexturePosition.base.index = (ui8)methodDatas[2].index;\n        v.dispTexturePosition.base.atlas = atlasIndices[2];\n        v.texturePosition.overlay.index = (ui8)methodDatas[3].index;\n        v.texturePosition.overlay.atlas = atlasIndices[3];\n        v.normTexturePosition.overlay.index = (ui8)methodDatas[4].index;\n        v.normTexturePosition.overlay.atlas = atlasIndices[4];\n        v.dispTexturePosition.overlay.index = (ui8)methodDatas[5].index;\n        v.dispTexturePosition.overlay.atlas = atlasIndices[5];\n        \n        v.textureDims = methodDatas[0].size;\n        v.overlayTextureDims = methodDatas[3].size;\n        v.blendMode = blendMode;\n        v.face = (ui8)face;\n    }\n    // Set texture coordinates\n    quad->verts[0].tex.x = (ui8)(UV_0 + uOffset);\n    quad->verts[0].tex.y = (ui8)(UV_1 + vOffset);\n    quad->verts[1].tex.x = (ui8)(UV_0 + uOffset);\n    quad->verts[1].tex.y = (ui8)(UV_0 + vOffset);\n    quad->verts[2].tex.x = (ui8)(UV_1 + uOffset);\n    quad->verts[2].tex.y = (ui8)(UV_0 + vOffset);\n    quad->verts[3].tex.x = (ui8)(UV_1 + uOffset);\n    quad->verts[3].tex.y = (ui8)(UV_1 + vOffset);\n\n    // Check against lowest and highest for culling in render\n    // TODO(Ben): Think about this more\n    if (quad->v.v0.position.x < m_lowestX) m_lowestX = quad->v.v0.position.x;\n    if (quad->v.v0.position.x > m_highestX) m_highestX = quad->v.v0.position.x;\n    if (quad->v.v0.position.y < m_lowestY) m_lowestY = quad->v.v0.position.y;\n    if (quad->v.v0.position.y > m_highestY) m_highestY = quad->v.v0.position.y;\n    if (quad->v.v0.position.z < m_lowestZ) m_lowestZ = quad->v.v0.position.z;\n    if (quad->v.v0.position.z > m_highestZ) m_highestZ = quad->v.v0.position.z;\n\n    m_numQuads -= tryMergeQuad(quad, quads, face, rightAxis, frontAxis, leftOffset, backOffset, rightStretchIndex, texOffset);\n}\n\nstruct FloraQuadData {\n    color3 blockColor[2];\n    BlockTextureMethodData methodDatas[6];\n    ui8 atlasIndices[6];\n    ui8 blendMode;\n    ui8 uOffset;\n    ui8 vOffset;\n    const BlockTexture* texture;\n};\n\n//adds a flora mesh\nvoid ChunkMesher::addFlora() {\n    FloraQuadData data;\n\n    data.texture = block->textures[0];\n    // Get colors\n    // TODO(Ben): altColors\n    data.texture->layers.base.getFinalColor(data.blockColor[B_INDEX],\n                                heightData->temperature,\n                                heightData->humidity, 0);\n    data.texture->layers.base.getFinalColor(data.blockColor[O_INDEX],\n                                heightData->temperature,\n                                heightData->humidity, 0);\n\n    // Get texturing parameters\n    data.blendMode = getBlendMode(data.texture->blendMode);\n    data.texture->layers.base.getBlockTextureMethodData(m_textureMethodParams[0][B_INDEX], data.blockColor[B_INDEX], data.methodDatas[0]);\n    data.texture->layers.base.getNormalTextureMethodData(m_textureMethodParams[0][B_INDEX], data.blockColor[B_INDEX], data.methodDatas[1]);\n    data.texture->layers.base.getDispTextureMethodData(m_textureMethodParams[0][B_INDEX], data.blockColor[B_INDEX], data.methodDatas[2]);\n    data.texture->layers.overlay.getBlockTextureMethodData(m_textureMethodParams[0][O_INDEX], data.blockColor[O_INDEX], data.methodDatas[3]);\n    data.texture->layers.overlay.getNormalTextureMethodData(m_textureMethodParams[0][O_INDEX], data.blockColor[O_INDEX], data.methodDatas[4]);\n    data.texture->layers.overlay.getDispTextureMethodData(m_textureMethodParams[0][O_INDEX], data.blockColor[O_INDEX], data.methodDatas[5]);\n    for (int i = 0; i < 6; i++) {\n        data.atlasIndices[i] = (ui8)(data.methodDatas[i].index / ATLAS_SIZE);\n        data.methodDatas[i].index &= ATLAS_MODULUS_BITS;\n    }\n\n    i32v3 pos(bx, by, bz);\n    data.uOffset = (ui8)(pos[FACE_AXIS[0][0]] * FACE_AXIS_SIGN[0][0]);\n    data.vOffset = (ui8)(pos[FACE_AXIS[0][1]] * FACE_AXIS_SIGN[0][1]);\n    int r;\n    switch (block->meshType) {\n        case MeshType::LEAVES:\n\n            break;\n        case MeshType::CROSSFLORA:\n            //Generate a random number between 0 and 3 inclusive\n            r = std::bind(std::uniform_int_distribution<int>(0, NUM_CROSSFLORA_MESHES-1), std::mt19937(/*getPositionSeed(mi.nx, mi.nz)*/))();\n\n            ChunkMesher::addFloraQuad(VoxelMesher::crossFloraVertices[r], data);\n            ChunkMesher::addFloraQuad(VoxelMesher::crossFloraVertices[r] + 4, data);\n            break;\n        case MeshType::TRIANGLE:\n            //Generate a random number between 0 and 3 inclusive\n            r = std::bind(std::uniform_int_distribution<int>(0, NUM_FLORA_MESHES-1), std::mt19937(/*getPositionSeed(mi.nx, mi.nz)*/))();\n\n            ChunkMesher::addFloraQuad(VoxelMesher::floraVertices[r], data);\n            ChunkMesher::addFloraQuad(VoxelMesher::floraVertices[r] + 4, data);\n            ChunkMesher::addFloraQuad(VoxelMesher::floraVertices[r] + 8, data);\n            break;\n        default:\n            break;\n    }\n}\n\nvoid ChunkMesher::addFloraQuad(const ui8v3* positions, FloraQuadData& data) {\n\n    m_floraQuads.emplace_back();\n    VoxelQuad& quad = m_floraQuads.back();\n\n    for (int i = 0; i < 4; i++) {\n        BlockVertex& v = quad.verts[i];\n        v.position = positions[i] + voxelPosOffset;\n\n        v.color = data.blockColor[B_INDEX];\n        v.overlayColor = data.blockColor[O_INDEX];\n\n        // TODO(Ben) array?\n        v.texturePosition.base.index = (ui8)data.methodDatas[0].index;\n        v.texturePosition.base.atlas = data.atlasIndices[0];\n        v.normTexturePosition.base.index = (ui8)data.methodDatas[1].index;\n        v.normTexturePosition.base.atlas = data.atlasIndices[1];\n        v.dispTexturePosition.base.index = (ui8)data.methodDatas[2].index;\n        v.dispTexturePosition.base.atlas = data.atlasIndices[2];\n        v.texturePosition.overlay.index = (ui8)data.methodDatas[3].index;\n        v.texturePosition.overlay.atlas = data.atlasIndices[3];\n        v.normTexturePosition.overlay.index = (ui8)data.methodDatas[4].index;\n        v.normTexturePosition.overlay.atlas = data.atlasIndices[4];\n        v.dispTexturePosition.overlay.index = (ui8)data.methodDatas[5].index;\n        v.dispTexturePosition.overlay.atlas = data.atlasIndices[5];\n\n        v.textureDims = data.methodDatas[0].size;\n        v.overlayTextureDims = data.methodDatas[3].size;\n        v.blendMode = data.blendMode;\n        v.face = (ui8)vvox::Cardinal::Y_POS;\n    }\n    // Set texture coordinates\n    quad.verts[0].tex.x = (ui8)(UV_0 + data.uOffset);\n    quad.verts[0].tex.y = (ui8)(UV_1 + data.vOffset);\n    quad.verts[1].tex.x = (ui8)(UV_0 + data.uOffset);\n    quad.verts[1].tex.y = (ui8)(UV_0 + data.vOffset);\n    quad.verts[2].tex.x = (ui8)(UV_1 + data.uOffset);\n    quad.verts[2].tex.y = (ui8)(UV_0 + data.vOffset);\n    quad.verts[3].tex.x = (ui8)(UV_1 + data.uOffset);\n    quad.verts[3].tex.y = (ui8)(UV_1 + data.vOffset);\n\n    // Check against lowest and highest for culling in render\n    // TODO(Ben): Think about this more\n    if (quad.v.v0.position.x < m_lowestX) m_lowestX = quad.v.v0.position.x;\n    if (quad.v.v0.position.x > m_highestX) m_highestX = quad.v.v0.position.x;\n    if (quad.v.v0.position.y < m_lowestY) m_lowestY = quad.v.v0.position.y;\n    if (quad.v.v0.position.y > m_highestY) m_highestY = quad.v.v0.position.y;\n    if (quad.v.v0.position.z < m_lowestZ) m_lowestZ = quad.v.v0.position.z;\n    if (quad.v.v0.position.z > m_highestZ) m_highestZ = quad.v.v0.position.z;\n}\n\n\nint ChunkMesher::tryMergeQuad(VoxelQuad* quad, std::vector<VoxelQuad>& quads, int face, int rightAxis, int frontAxis, int leftOffset, int backOffset, int rightStretchIndex, const ui8v2& texOffset) {\n    int rv = 0;\n    i16 quadIndex = quads.size() - 1;\n    if (quad->v.v0 == quad->v.v3 && quad->v.v1 == quad->v.v2) {\n        quad->v.v0.mesherFlags |= MESH_FLAG_MERGE_RIGHT;\n        ui16 leftIndex = m_quadIndices[blockIndex + leftOffset][face];\n        // Check left merge\n        if (leftIndex != NO_QUAD_INDEX) {\n            VoxelQuad& lQuad = quads[leftIndex];\n            if (((lQuad.v.v0.mesherFlags & MESH_FLAG_MERGE_RIGHT) != 0) &&\n                lQuad.v.v0.position[frontAxis] == quad->v.v0.position[frontAxis] &&\n                lQuad.v.v1.position[frontAxis] == quad->v.v1.position[frontAxis] &&\n                lQuad.v.v0 == quad->v.v0 && lQuad.v.v1 == quad->v.v1) {\n                // Stretch the previous quad\n                lQuad.verts[rightStretchIndex].position[rightAxis] += QUAD_SIZE;\n                lQuad.verts[rightStretchIndex].tex.x += texOffset.x;\n                lQuad.verts[rightStretchIndex + 1].position[rightAxis] += QUAD_SIZE;\n                lQuad.verts[rightStretchIndex + 1].tex.x += texOffset.x;\n                // Remove the current quad\n                quads.pop_back();\n                ++rv;\n                quadIndex = leftIndex;\n                quad = &lQuad;\n            }\n        }\n    }\n    // Check back merge\n    if (quad->v.v0 == quad->v.v1 && quad->v.v2 == quad->v.v3) {\n        quad->v.v0.mesherFlags |= MESH_FLAG_MERGE_FRONT;\n        int backIndex = m_quadIndices[blockIndex + backOffset][face];\n        if (backIndex != NO_QUAD_INDEX) {\n            VoxelQuad* bQuad = &quads[backIndex];\n            while (!(bQuad->v.v0.mesherFlags & MESH_FLAG_ACTIVE)) {\n                backIndex = bQuad->v.replaceQuad;\n                bQuad = &quads[backIndex];\n            }\n            if (((bQuad->v.v0.mesherFlags & MESH_FLAG_MERGE_FRONT) != 0) &&\n                bQuad->v.v0.position[rightAxis] == quad->v.v0.position[rightAxis] &&\n                bQuad->v.v2.position[rightAxis] == quad->v.v2.position[rightAxis] &&\n                bQuad->v.v0 == quad->v.v0 && bQuad->v.v1 == quad->v.v1) {\n                bQuad->v.v0.position[frontAxis] += QUAD_SIZE;\n                bQuad->v.v0.tex.y += texOffset.y;\n                bQuad->v.v3.position[frontAxis] += QUAD_SIZE;\n                bQuad->v.v3.tex.y += texOffset.y;\n                quadIndex = backIndex;\n                // Mark as not in use\n                quad->v.v0.mesherFlags = 0;\n                quad->v.replaceQuad = backIndex;\n                ++rv;\n            }\n        }\n    }\n    // Mark quadIndices so we can merge this quad later\n    m_quadIndices[blockIndex][face] = quadIndex;\n    // Return number of merges\n    return rv;\n}\n\n//Gets the liquid level from a block index\n#define LEVEL(i) ((_blockIDData[i] == 0) ? 0 : (((nextBlock = &GETBLOCK(_blockIDData[i]))->caIndex == block.caIndex) ? nextBlock->waterMeshLevel : 0))\n\n#define CALCULATE_LIQUID_VERTEX_HEIGHT(height, heightA, heightB, cornerIndex) \\\n    div = 0; \\\n    tot = 0; \\\n    if (heightA) { \\\n        tot += heightA; \\\n        div++; \\\n    } \\\n    \\\n    if (heightB) { \\\n        tot += heightB; \\\n        div++; \\\n    } \\\n    \\\n    if (div) { \\\n        int lvl = LEVEL(cornerIndex); \\\n        if (lvl) { \\\n            tot += lvl; \\\n            div++; \\\n        } \\\n        height = (height + (tot / (float)maxLevel)) / (div + 1); \\\n    } \n    \n   \n//END CALCULATE_LIQUID_VERTEX_HEIGHT\n\n// TODO(Ben): Instead of 8 verts per box, share vertices and index into it!\nvoid ChunkMesher::addLiquid() {\n  //  const Block &block = (*m_blocks)[mi.btype];\n  //  Block* nextBlock;\n  //  i32 nextBlockID;\n  //  const i32 wc = mi.wc;\n  //  i32 x = mi.x;\n  //  i32 y = mi.y;\n  //  i32 z = mi.z;\n\n  //  RenderTask* task = mi.task;\n\n  //  const i32 maxLevel = 100;\n\n  //  float liquidLevel = block.waterMeshLevel / (float)maxLevel;\n  //  float fallingReduction = 0.0f;\n\n  //  bool faces[6] = { false, false, false, false, false, false };\n\n  //  float backLeftHeight = liquidLevel;\n  //  float backRightHeight = liquidLevel;\n  //  float frontRightHeight = liquidLevel;\n  //  float frontLeftHeight = liquidLevel;\n\n  //  const i32 MIN_ALPHA = 75;\n  //  const i32 MAX_ALPHA = 175;\n  //  const i32 ALPHA_RANGE = MAX_ALPHA - MIN_ALPHA;\n\n  //  ui8 backRightAlpha, frontRightAlpha, frontLeftAlpha, backLeftAlpha;\n\n  //  i32 textureUnit = 0;\n\n  //  i32 div;\n  //  i32 tot;\n\n  //  i32 left, right, back, front, bottom;\n\n  //  ui8 uOff = x * 7;\n  //  ui8 vOff = 224 - z * 7;\n\n  //  ui8 temperature = chunkGridData->heightData[x + z*CHUNK_WIDTH].temperature;\n  //  ui8 depth = chunkGridData->heightData[x + z*CHUNK_WIDTH].depth;\n\n  //  ColorRGB8 color;// = GameManager::texturePackLoader->getColorMap(TerrainGenerator::DefaultColorMaps::WATER)[depth * 256 + temperature];\n\n  //  ui8 sunlight = _sunlightData[wc];\n  //  ColorRGB8 lampLight((_lampLightData[wc] & LAMP_RED_MASK) >> LAMP_RED_SHIFT,\n  //                      (_lampLightData[wc] & LAMP_GREEN_MASK) >> LAMP_GREEN_SHIFT,\n  //                      _lampLightData[wc] & LAMP_BLUE_MASK);\n\n  //  sunlight = (ui8)(255.0f*(LIGHT_OFFSET + pow(LIGHT_MULT, MAXLIGHT - sunlight)));\n  //  lampLight.r = (ui8)(255.0f*(LIGHT_OFFSET + pow(LIGHT_MULT, MAXLIGHT - lampLight.r)));\n  //  lampLight.g = (ui8)(255.0f*(LIGHT_OFFSET + pow(LIGHT_MULT, MAXLIGHT - lampLight.g)));\n  //  lampLight.b = (ui8)(255.0f*(LIGHT_OFFSET + pow(LIGHT_MULT, MAXLIGHT - lampLight.b)));\n\n  //  nextBlockID = _blockIDData[wc + PADDED_OFFSETS::BOTTOM];\n  //  nextBlock = &GETBLOCK(nextBlockID);\n  //  //Check if the block is falling\n  //  if (nextBlockID == 0 || nextBlock->waterBreak || (nextBlock->caIndex == block.caIndex && nextBlock->waterMeshLevel != maxLevel)) {\n  //      memset(faces, 1, 6); //all faces are active\n  ////      backLeftHeight = backRightHeight = frontLeftHeight = frontRightHeight \n  //      fallingReduction = 1.0f;\n  //  } else {\n\n  //      //Get occlusion\n  //      nextBlock = &GETBLOCK(_blockIDData[wc + PADDED_OFFSETS::LEFT]);\n  //      faces[XNEG] = ((nextBlock->caIndex != block.caIndex) && (nextBlock->occlude == BlockOcclusion::NONE));\n\n  //      nextBlock = &GETBLOCK(_blockIDData[wc + PADDED_OFFSETS::BACK]);\n  //      faces[ZNEG] = ((nextBlock->caIndex != block.caIndex) && (nextBlock->occlude == BlockOcclusion::NONE));\n\n  //      nextBlock = &GETBLOCK(_blockIDData[wc + PADDED_OFFSETS::RIGHT]);\n  //      faces[XPOS] = ((nextBlock->caIndex != block.caIndex) && (nextBlock->occlude == BlockOcclusion::NONE));\n\n  //      nextBlock = &GETBLOCK(_blockIDData[wc + PADDED_OFFSETS::FRONT]);\n  //      faces[ZPOS] = ((nextBlock->caIndex != block.caIndex) && (nextBlock->occlude == BlockOcclusion::NONE));\n\n  //      nextBlock = &GETBLOCK(_blockIDData[wc + PADDED_OFFSETS::BOTTOM]);\n  //      faces[YNEG] = ((nextBlock->caIndex != block.caIndex) && (nextBlock->occlude == BlockOcclusion::NONE));\n  //  }\n\n  //  left = LEVEL(wc + PADDED_OFFSETS::LEFT);\n  //  right = LEVEL(wc + PADDED_OFFSETS::RIGHT);\n  //  back = LEVEL(wc + PADDED_OFFSETS::BACK);\n  //  front = LEVEL(wc + PADDED_OFFSETS::FRONT);\n  //  bottom = LEVEL(wc + PADDED_OFFSETS::BOTTOM);\n\n  //  //Calculate the liquid levels\n\n  //  //Back Left Vertex\n  //  CALCULATE_LIQUID_VERTEX_HEIGHT(backLeftHeight, left, back, wc + PADDED_OFFSETS::BACK_LEFT);\n\n  //  //Back Right Vertex\n  //  CALCULATE_LIQUID_VERTEX_HEIGHT(backRightHeight, right, back, wc + PADDED_OFFSETS::BACK_RIGHT);\n\n  //  //Front Right Vertex\n  //  CALCULATE_LIQUID_VERTEX_HEIGHT(frontRightHeight, right, front, wc + PADDED_OFFSETS::FRONT_RIGHT);\n\n  //  //Front Left Vertex\n  //  CALCULATE_LIQUID_VERTEX_HEIGHT(frontLeftHeight, left, front, wc + PADDED_OFFSETS::FRONT_LEFT);\n\n  //  //only occlude top if we are a full water block and our sides arent down at all\n  //  if (liquidLevel == 1.0f && backRightHeight == 1.0f && backLeftHeight == 1.0f && frontLeftHeight == 1.0f && frontRightHeight == 1.0f) {\n  //      nextBlock = &GETBLOCK(_blockIDData[wc + PADDED_OFFSETS::TOP]);\n  //      faces[YPOS] = ((nextBlock->caIndex != block.caIndex) && (nextBlock->occlude == BlockOcclusion::NONE));\n  //  } else {\n  //      faces[YPOS] = true;\n  //  }\n  //  \n  //  //Compute alpha\n  //  if (bottom == maxLevel) {\n  //      backRightAlpha = backLeftAlpha = frontRightAlpha = frontLeftAlpha = MAX_ALPHA;\n  //  } else {\n  //      backRightAlpha = (ui8)(backRightHeight * ALPHA_RANGE + MIN_ALPHA);\n  //      backLeftAlpha = (ui8)(backLeftHeight * ALPHA_RANGE + MIN_ALPHA);\n  //      frontRightAlpha = (ui8)(frontRightHeight * ALPHA_RANGE + MIN_ALPHA);\n  //      frontLeftAlpha = (ui8)(frontLeftHeight * ALPHA_RANGE + MIN_ALPHA);\n  //  }\n\n  //  //Add vertices for the faces\n  //  if (faces[YNEG]){\n\n  //      VoxelMesher::makeLiquidFace(_waterVboVerts, mi.liquidIndex, uOff, vOff, lampLight, sunlight, color, textureUnit);\n  //      \n  //      _waterVboVerts[mi.liquidIndex].position[0] = x + VoxelMesher::liquidVertices[48];\n  //      _waterVboVerts[mi.liquidIndex].position[1] = y + VoxelMesher::liquidVertices[49] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex].position[2] = z + VoxelMesher::liquidVertices[50];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[0] = x + VoxelMesher::liquidVertices[51];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[1] = y + VoxelMesher::liquidVertices[52] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 1].position[2] = z + VoxelMesher::liquidVertices[53];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[0] = x + VoxelMesher::liquidVertices[54];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[1] = y + VoxelMesher::liquidVertices[55] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 2].position[2] = z + VoxelMesher::liquidVertices[56];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[0] = x + VoxelMesher::liquidVertices[57];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[1] = y + VoxelMesher::liquidVertices[58] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 3].position[2] = z + VoxelMesher::liquidVertices[59];\n\n  //      //set alpha\n  //      _waterVboVerts[mi.liquidIndex].color.a = backLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 1].color.a = backRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 2].color.a = frontRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 3].color.a = backLeftAlpha;\n\n  //      mi.liquidIndex += 4;\n  //  }\n\n  //  if (faces[ZPOS]){\n\n  //      VoxelMesher::makeLiquidFace(_waterVboVerts, mi.liquidIndex, uOff, vOff, lampLight, sunlight, color, textureUnit);\n\n  //      _waterVboVerts[mi.liquidIndex].position[0] = x + VoxelMesher::liquidVertices[0];\n  //      _waterVboVerts[mi.liquidIndex].position[1] = y + frontLeftHeight;\n  //      _waterVboVerts[mi.liquidIndex].position[2] = z + VoxelMesher::liquidVertices[2];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[0] = x + VoxelMesher::liquidVertices[3];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[1] = y + VoxelMesher::liquidVertices[4] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 1].position[2] = z + VoxelMesher::liquidVertices[5];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[0] = x + VoxelMesher::liquidVertices[6];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[1] = y + VoxelMesher::liquidVertices[7] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 2].position[2] = z + VoxelMesher::liquidVertices[8];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[0] = x + VoxelMesher::liquidVertices[9];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[1] = y + frontRightHeight;\n  //      _waterVboVerts[mi.liquidIndex + 3].position[2] = z + VoxelMesher::liquidVertices[11];\n\n  //      _waterVboVerts[mi.liquidIndex].color.a = frontLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 1].color.a = frontLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 2].color.a = frontRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 3].color.a = frontRightAlpha;\n\n  //      mi.liquidIndex += 4;\n  //  }\n\n  //  if (faces[YPOS]){\n\n  //      VoxelMesher::makeLiquidFace(_waterVboVerts, mi.liquidIndex, uOff, vOff, lampLight, sunlight, color, textureUnit);\n\n  //      _waterVboVerts.resize(_waterVboVerts.size() + 4);\n  //      _waterVboVerts[mi.liquidIndex].position[0] = x + VoxelMesher::liquidVertices[24];\n  //      _waterVboVerts[mi.liquidIndex].position[1] = y + backLeftHeight;\n  //      _waterVboVerts[mi.liquidIndex].position[2] = z + VoxelMesher::liquidVertices[26];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[0] = x + VoxelMesher::liquidVertices[27];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[1] = y + frontLeftHeight;\n  //      _waterVboVerts[mi.liquidIndex + 1].position[2] = z + VoxelMesher::liquidVertices[29];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[0] = x + VoxelMesher::liquidVertices[30];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[1] = y + frontRightHeight;\n  //      _waterVboVerts[mi.liquidIndex + 2].position[2] = z + VoxelMesher::liquidVertices[32];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[0] = x + VoxelMesher::liquidVertices[33];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[1] = y + backRightHeight;\n  //      _waterVboVerts[mi.liquidIndex + 3].position[2] = z + VoxelMesher::liquidVertices[35];\n\n  //      _waterVboVerts[mi.liquidIndex].color.a = backLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 1].color.a = frontLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 2].color.a = frontRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 3].color.a = backRightAlpha;\n\n  //      mi.liquidIndex += 4;\n  //  }\n\n  //  if (faces[ZNEG]){\n\n  //      VoxelMesher::makeLiquidFace(_waterVboVerts, mi.liquidIndex, uOff, vOff, lampLight, sunlight, color, textureUnit);\n\n  //      _waterVboVerts[mi.liquidIndex].position[0] = x + VoxelMesher::liquidVertices[60];\n  //      _waterVboVerts[mi.liquidIndex].position[1] = y + backRightHeight;\n  //      _waterVboVerts[mi.liquidIndex].position[2] = z + VoxelMesher::liquidVertices[62];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[0] = x + VoxelMesher::liquidVertices[63];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[1] = y + VoxelMesher::liquidVertices[64] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 1].position[2] = z + VoxelMesher::liquidVertices[65];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[0] = x + VoxelMesher::liquidVertices[66];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[1] = y + VoxelMesher::liquidVertices[67] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 2].position[2] = z + VoxelMesher::liquidVertices[68];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[0] = x + VoxelMesher::liquidVertices[69];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[1] = y + backLeftHeight;\n  //      _waterVboVerts[mi.liquidIndex + 3].position[2] = z + VoxelMesher::liquidVertices[71];\n\n  //      _waterVboVerts[mi.liquidIndex].color.a = backRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 1].color.a = backRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 2].color.a = backLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 3].color.a = backLeftAlpha;\n\n  //      mi.liquidIndex += 4;\n  //  }\n  //  if (faces[XPOS]){\n\n  //      VoxelMesher::makeLiquidFace(_waterVboVerts, mi.liquidIndex, uOff, vOff, lampLight, sunlight, color, textureUnit);\n\n  //      _waterVboVerts[mi.liquidIndex].position.x = x + VoxelMesher::liquidVertices[12];\n  //      _waterVboVerts[mi.liquidIndex].position.y = y + frontRightHeight;\n  //      _waterVboVerts[mi.liquidIndex].position.z = z + VoxelMesher::liquidVertices[14];\n  //      _waterVboVerts[mi.liquidIndex + 1].position.x = x + VoxelMesher::liquidVertices[15];\n  //      _waterVboVerts[mi.liquidIndex + 1].position.y = y + VoxelMesher::liquidVertices[16] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 1].position.z = z + VoxelMesher::liquidVertices[17];\n  //      _waterVboVerts[mi.liquidIndex + 2].position.x = x + VoxelMesher::liquidVertices[18];\n  //      _waterVboVerts[mi.liquidIndex + 2].position.y = y + VoxelMesher::liquidVertices[19] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 2].position.z = z + VoxelMesher::liquidVertices[20];\n  //      _waterVboVerts[mi.liquidIndex + 3].position.x = x + VoxelMesher::liquidVertices[21];\n  //      _waterVboVerts[mi.liquidIndex + 3].position.y = y + backRightHeight;\n  //      _waterVboVerts[mi.liquidIndex + 3].position.z = z + VoxelMesher::liquidVertices[23];\n\n  //      _waterVboVerts[mi.liquidIndex].color.a = frontRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 1].color.a = frontRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 2].color.a = backRightAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 3].color.a = backRightAlpha;\n\n  //      mi.liquidIndex += 4;\n  //  }\n  //  if (faces[XNEG]){\n\n  //      VoxelMesher::makeLiquidFace(_waterVboVerts, mi.liquidIndex, uOff, vOff, lampLight, sunlight, color, textureUnit);\n\n  //      _waterVboVerts[mi.liquidIndex].position[0] = x + VoxelMesher::liquidVertices[36];\n  //      _waterVboVerts[mi.liquidIndex].position[1] = y + backLeftHeight;\n  //      _waterVboVerts[mi.liquidIndex].position[2] = z + VoxelMesher::liquidVertices[38];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[0] = x + VoxelMesher::liquidVertices[39];\n  //      _waterVboVerts[mi.liquidIndex + 1].position[1] = y + VoxelMesher::liquidVertices[40] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 1].position[2] = z + VoxelMesher::liquidVertices[41];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[0] = x + VoxelMesher::liquidVertices[42];\n  //      _waterVboVerts[mi.liquidIndex + 2].position[1] = y + VoxelMesher::liquidVertices[43] - fallingReduction;\n  //      _waterVboVerts[mi.liquidIndex + 2].position[2] = z + VoxelMesher::liquidVertices[44];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[0] = x + VoxelMesher::liquidVertices[45];\n  //      _waterVboVerts[mi.liquidIndex + 3].position[1] = y + frontLeftHeight;\n  //      _waterVboVerts[mi.liquidIndex + 3].position[2] = z + VoxelMesher::liquidVertices[47];\n\n  //      _waterVboVerts[mi.liquidIndex].color.a = backLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 1].color.a = backLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 2].color.a = frontLeftAlpha;\n  //      _waterVboVerts[mi.liquidIndex + 3].color.a = frontLeftAlpha;\n\n  //      mi.liquidIndex += 4;\n  //  }\n}\n\nint ChunkMesher::getLiquidLevel(int blockIndex, const Block& block) {\n    int val = GETBLOCKID(blockData[blockIndex]); // Get block ID\n    val = val - block.liquidStartID;\n    if (val < 0) return 0;\n    if (val > block.liquidLevels) return 0;\n    return val;\n}\n\nbool ChunkMesher::shouldRenderFace(int offset) {\n    const Block& neighbor = blocks->operator[](blockData[blockIndex + offset]);\n    if (neighbor.occlude == BlockOcclusion::ALL) return false;\n    if ((neighbor.occlude == BlockOcclusion::SELF) && (blockID == neighbor.ID)) return false;\n    return true;\n}\n\nint ChunkMesher::getOcclusion(const Block& block) {\n    if (block.occlude == BlockOcclusion::ALL) return 1;\n    if ((block.occlude == BlockOcclusion::SELF) && (blockID == block.ID)) return 1;\n    return 0;\n}\n\nui8 ChunkMesher::getBlendMode(const BlendType& blendType) {\n    // Shader interprets this with bitwise ops\n    ubyte blendMode = 0x14; //0x14 = 00 01 01 00\n    switch (blendType) {\n        case BlendType::ALPHA:\n            blendMode |= 1; //Sets blendMode to 00 01 01 01\n            break;\n        case BlendType::ADD:\n            blendMode += 4; //Sets blendMode to 00 01 10 00\n            break;\n        case BlendType::SUBTRACT:\n            blendMode -= 4; //Sets blendMode to 00 01 00 00\n            break;\n        case BlendType::MULTIPLY:\n            blendMode -= 16; //Sets blendMode to 00 00 01 00\n            break;\n    }\n    return blendMode;\n}\n\nvoid ChunkMesher::buildTransparentVao(ChunkMesh& cm) {\n    glGenVertexArrays(1, &(cm.transVaoID));\n    glBindVertexArray(cm.transVaoID);\n\n    glBindBuffer(GL_ARRAY_BUFFER, cm.transVboID);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cm.transIndexID);\n\n    for (int i = 0; i < 8; i++) {\n        glEnableVertexAttribArray(i);\n    }\n\n    // TODO(Ben): Might be wrong\n    // vPosition_Face\n    glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, position));\n    // vTex_Animation_BlendMode\n    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, tex));\n    // vTexturePos\n    glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, texturePosition));\n    // vNormTexturePos\n    glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, normTexturePosition));\n    // vDispTexturePos\n    glVertexAttribPointer(4, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, dispTexturePosition));\n    // vTexDims\n    glVertexAttribPointer(5, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, textureDims));\n    // vColor\n    glVertexAttribPointer(6, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(BlockVertex), offsetptr(BlockVertex, color));\n    // vOverlayColor\n    glVertexAttribPointer(7, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(BlockVertex), offsetptr(BlockVertex, overlayColor));\n\n    glBindVertexArray(0);\n}\n\nvoid ChunkMesher::buildCutoutVao(ChunkMesh& cm) {\n    glGenVertexArrays(1, &(cm.cutoutVaoID));\n    glBindVertexArray(cm.cutoutVaoID);\n\n    glBindBuffer(GL_ARRAY_BUFFER, cm.cutoutVboID);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ChunkRenderer::sharedIBO);\n\n    for (int i = 0; i < 8; i++) {\n        glEnableVertexAttribArray(i);\n    }\n\n    // vPosition_Face\n    glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, position));\n    // vTex_Animation_BlendMode\n    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, tex));\n    // vTexturePos\n    glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, texturePosition));\n    // vNormTexturePos\n    glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, normTexturePosition));\n    // vDispTexturePos\n    glVertexAttribPointer(4, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, dispTexturePosition));\n    // vTexDims\n    glVertexAttribPointer(5, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, textureDims));\n    // vColor\n    glVertexAttribPointer(6, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(BlockVertex), offsetptr(BlockVertex, color));\n    // vOverlayColor\n    glVertexAttribPointer(7, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(BlockVertex), offsetptr(BlockVertex, overlayColor));\n\n    glBindVertexArray(0);\n}\n\nvoid ChunkMesher::buildVao(ChunkMesh& cm) {\n    glGenVertexArrays(1, &(cm.vaoID));\n    glBindVertexArray(cm.vaoID);\n    glBindBuffer(GL_ARRAY_BUFFER, cm.vboID);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ChunkRenderer::sharedIBO);\n\n    for (int i = 0; i < 8; i++) {\n        glEnableVertexAttribArray(i);\n    }\n\n    // vPosition_Face\n    glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, position));\n    // vTex_Animation_BlendMode\n    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, tex));\n    // vTexturePos\n    glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, texturePosition));\n    // vNormTexturePos\n    glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, normTexturePosition));\n    // vDispTexturePos\n    glVertexAttribPointer(4, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, dispTexturePosition));\n    // vTexDims\n    glVertexAttribPointer(5, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(BlockVertex), offsetptr(BlockVertex, textureDims));\n    // vColor\n    glVertexAttribPointer(6, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(BlockVertex), offsetptr(BlockVertex, color));\n    // vOverlayColor\n    glVertexAttribPointer(7, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(BlockVertex), offsetptr(BlockVertex, overlayColor));\n\n    glBindVertexArray(0);\n}\n\nvoid ChunkMesher::buildWaterVao(ChunkMesh& cm) {\n    glGenVertexArrays(1, &(cm.waterVaoID));\n    glBindVertexArray(cm.waterVaoID);\n    glBindBuffer(GL_ARRAY_BUFFER, cm.waterVboID);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ChunkRenderer::sharedIBO);\n\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n    glEnableVertexAttribArray(2);\n    glEnableVertexAttribArray(3);\n\n    glBindBuffer(GL_ARRAY_BUFFER, cm.waterVboID);\n\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(LiquidVertex), 0);\n    //uvs_texUnit_texIndex\n    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(LiquidVertex), (char *)12);\n    //color\n    glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(LiquidVertex), (char *)16);\n    //light\n    glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(LiquidVertex), (char *)20);\n\n    glBindVertexArray(0);\n}"
  },
  {
    "path": "SoA/ChunkMesher.h",
    "content": "#pragma once\n#include \"Vertex.h\"\n#include \"BlockData.h\"\n#include \"Chunk.h\"\n#include \"ChunkMesh.h\"\n#include \"ChunkMeshTask.h\"\n\nclass BlockPack;\nclass BlockTextureLayer;\nclass ChunkMeshData;\nstruct BlockTexture;\nstruct PlanetHeightData;\nstruct FloraQuadData;\n\n// Sizes For A Padded Chunk\nconst int PADDED_CHUNK_WIDTH = (CHUNK_WIDTH + 2);\nconst int PADDED_CHUNK_LAYER = (PADDED_CHUNK_WIDTH * PADDED_CHUNK_WIDTH);\nconst int PADDED_CHUNK_SIZE = (PADDED_CHUNK_LAYER * PADDED_CHUNK_WIDTH);\n\n// !!! IMPORTANT !!!\n// TODO(BEN): Make a class for complex Chunk Mesh Splicing. Store plenty of metadata in RAM about the regions in each mesh and just do a CPU copy to align them all and mix them around. Then meshes can be remeshed, rendered, recombined, at will.\n// Requirements: Each chunk is only meshed when it needs to, as they do now.\n// Rather than remeshing when combining and splitting, we just download the data from the GPU (or cache it compressed in RAM on 64 bit systems?)\n// Copy it around, and re-upload.\n// glBufferSubData and maybe even re-use buffers to minimize bandwidth???\n\n// each worker thread gets one of these\n// This class is too big to statically allocate\nclass ChunkMesher {\npublic:\n    ChunkMesher():blocks(nullptr), m_chunkMeshData(nullptr){}\n\n    void init(const BlockPack* blocks);\n\n    // Easily creates chunk mesh synchronously.\n    CALLER_DELETE ChunkMesh* easyCreateChunkMesh(const Chunk* chunk, MeshTaskType type) {\n        prepareData(chunk);\n        ChunkMesh* mesh = new ChunkMesh;\n        mesh->position = chunk->getVoxelPosition().pos;\n        uploadMeshData(*mesh, createChunkMeshData(type));\n        return mesh;\n    }\n\n    // Call one of these before createChunkMesh\n    void prepareData(const Chunk* chunk);\n    // For use with threadpool\n    void prepareDataAsync(ChunkHandle& chunk, ChunkHandle neighbors[NUM_NEIGHBOR_HANDLES]);\n\n    // TODO(Ben): Unique ptr?\n    // Must call prepareData or prepareDataAsync first\n    CALLER_DELETE ChunkMeshData* createChunkMeshData(MeshTaskType type);\n\n    // Returns true if the mesh is renderable\n    static bool uploadMeshData(ChunkMesh& mesh, ChunkMeshData* meshData);\n\n    // Frees buffers AND deletes memory. mesh Pointer is invalid after calling.\n    static void freeChunkMesh(CALLEE_DELETE ChunkMesh* mesh);\n\n    void freeBuffers();\n\n    int bx, by, bz; // Block iterators\n    int blockIndex;\n    ui16 blockID;\n    const Block* block;\n    const PlanetHeightData* heightData;\n    ui8v3 voxelPosOffset;\n\n    // Heightmap data\n    PlanetHeightData heightDataBuffer[CHUNK_LAYER];\n    // Voxel data arrays\n    ui16 blockData[PADDED_CHUNK_SIZE];\n    ui16 tertiaryData[PADDED_CHUNK_SIZE];\n\n    const BlockPack* blocks;\n\n    VoxelPosition3D chunkVoxelPos;\nprivate:\n    void addBlock();\n    void addQuad(int face, int rightAxis, int frontAxis, int leftOffset, int backOffset, int rightStretchIndex, const ui8v2& texOffset, f32 ambientOcclusion[]);\n    void computeAmbientOcclusion(int upOffset, int frontOffset, int rightOffset, f32 ambientOcclusion[]);\n    void addFlora();\n    void addFloraQuad(const ui8v3* positions, FloraQuadData& data);\n    int tryMergeQuad(VoxelQuad* quad, std::vector<VoxelQuad>& quads, int face, int rightAxis, int frontAxis, int leftOffset, int backOffset, int rightStretchIndex, const ui8v2& texOffset);\n    void addLiquid();\n\n    int getLiquidLevel(int blockIndex, const Block& block);\n\n    bool shouldRenderFace(int offset);\n    int getOcclusion(const Block& block);\n\n    ui8 getBlendMode(const BlendType& blendType);\n\n    static void buildTransparentVao(ChunkMesh& cm);\n    static void buildCutoutVao(ChunkMesh& cm);\n    static void buildVao(ChunkMesh& cm);\n    static void buildWaterVao(ChunkMesh& cm);\n\n    ui16 m_quadIndices[PADDED_CHUNK_SIZE][6];\n    ui16 m_wvec[CHUNK_SIZE];\n\n    std::vector<BlockVertex> m_finalVerts[6];\n\n    std::vector<VoxelQuad> m_floraQuads;\n    std::vector<VoxelQuad> m_quads[6];\n    ui32 m_numQuads;\n\n    BlockTextureMethodParams m_textureMethodParams[6][2];\n\n    // TODO(Ben): Change this up a bit\n    std::vector<LiquidVertex> _waterVboVerts;\n\n    ChunkMeshData* m_chunkMeshData;\n\n    int m_highestY;\n    int m_lowestY;\n    int m_highestX;\n    int m_lowestX;\n    int m_highestZ;\n    int m_lowestZ;\n\n    const PlanetHeightData* m_chunkHeightData;\n\n    static PlanetHeightData defaultChunkHeightData[CHUNK_LAYER];\n\n    int wSize;\n\n//    ui32 m_finalQuads[7000];\n\n    BlockVertex m_topVerts[4100];\n\n};"
  },
  {
    "path": "SoA/ChunkQuery.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkQuery.h\"\n\n#include \"ChunkGrid.h\"\n\nvoid ChunkQuery::release() {\n    grid->releaseQuery(this);\n}"
  },
  {
    "path": "SoA/ChunkQuery.h",
    "content": "//\n// ChunkQuery.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 1 Aug 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Class for querying for a chunk with a certain generation level\n//\n\n#pragma once\n\n#ifndef ChunkQuery_h__\n#define ChunkQuery_h__\n\n#include \"ChunkHandle.h\"\n#include \"GenerateTask.h\"\n\n#include <Vorb/PtrRecycler.hpp>\n\nenum ChunkGenLevel { GEN_NONE = 0, GEN_TERRAIN, GEN_FLORA, GEN_SCRIPT, GEN_DONE };\n\nclass ChunkGrid;\n\nclass ChunkQuery {\n    friend class ChunkGenerator;\n    friend class GenerateTask;\n    friend class ChunkGrid;\npublic:\n    void release();\n\n    /// Blocks current thread until the query is finished\n    void block() {\n        std::unique_lock<std::mutex> lck(m_lock);\n        if (isFinished()) return;\n        m_cond.wait(lck);\n    }\n\n    const bool& isFinished() const { return m_isFinished; }\n\n    i32v3 chunkPos;\n    ChunkGenLevel genLevel;\n    GenerateTask genTask; ///< For if the query results in generation\n    ChunkHandle chunk; ///< Gets set on submitQuery\n    bool shouldRelease;\n    ChunkGrid* grid;\nprivate:\n    bool m_isFinished;\n    std::mutex m_lock;\n    std::condition_variable m_cond;\n};\n\n#endif // ChunkQuery_h__\n"
  },
  {
    "path": "SoA/ChunkRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkRenderer.h\"\n\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"ChunkMeshManager.h\"\n#include \"Frustum.h\"\n#include \"GameManager.h\"\n#include \"GameRenderParams.h\"\n#include \"GeometrySorter.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n#include \"SoaOptions.h\"\n#include \"soaUtils.h\"\n\nvolatile f32 ChunkRenderer::fadeDist = 1.0f;\nf32m4 ChunkRenderer::worldMatrix = f32m4(1.0f);\n\nVGIndexBuffer ChunkRenderer::sharedIBO = 0;\n\nvoid ChunkRenderer::init() {\n    // Not thread safe\n    if (!sharedIBO) { // Create shared IBO if needed\n        std::vector<ui32> indices;\n        const int NUM_INDICES = 589824;\n        indices.resize(NUM_INDICES);\n\n        ui32 j = 0u;\n        for (size_t i = 0; i < indices.size() - 12u; i += 6u) {\n            indices[i] = j;\n            indices[i + 1] = j + 1u;\n            indices[i + 2] = j + 2u;\n            indices[i + 3] = j + 2u;\n            indices[i + 4] = j + 3u;\n            indices[i + 5] = j;\n            j += 4u;\n        }\n\n        glGenBuffers(1, &sharedIBO);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sharedIBO);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, NUM_INDICES * sizeof(ui32), NULL, GL_STATIC_DRAW);\n        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, NUM_INDICES * sizeof(ui32), indices.data()); //arbitrarily set to 300000\n    }\n\n    { // Opaque\n        m_opaqueProgram = ShaderLoader::createProgramFromFile(\"Shaders/BlockShading/standardShading.vert\",\n                                                              \"Shaders/BlockShading/standardShading.frag\");\n        m_opaqueProgram.use();\n        glUniform1i(m_opaqueProgram.getUniform(\"unTextures\"), 0);\n    }\n    // TODO(Ben): Fix the shaders\n    { // Transparent\n   //     m_transparentProgram = ShaderLoader::createProgramFromFile(\"Shaders/BlockShading/standardShading.vert\",\n     //                                                              \"Shaders/BlockShading/cutoutShading.frag\");\n    }\n    { // Cutout\n        m_cutoutProgram = ShaderLoader::createProgramFromFile(\"Shaders/BlockShading/standardShading.vert\",\n                                                              \"Shaders/BlockShading/cutoutShading.frag\");\n        m_cutoutProgram.use();\n        glUniform1i(m_cutoutProgram.getUniform(\"unTextures\"), 0);\n    }\n    { // Water\n     //   m_waterProgram = ShaderLoader::createProgramFromFile(\"Shaders/WaterShading/WaterShading.vert\",\n     //                                                        \"Shaders/WaterShading/WaterShading.frag\");\n    }\n    vg::GLProgram::unuse();\n}\n\nvoid ChunkRenderer::dispose() {\n    if (m_opaqueProgram.isCreated()) m_opaqueProgram.dispose();\n    if (m_transparentProgram.isCreated()) m_transparentProgram.dispose();\n    if (m_cutoutProgram.isCreated()) m_cutoutProgram.dispose();\n    if (m_waterProgram.isCreated()) m_waterProgram.dispose();\n}\n\n// TODO: blockAmbient variables were going unused, what are they for?\n\nvoid ChunkRenderer::beginOpaque(VGTexture textureAtlas, const f32v3& sunDir, const f32v3& lightColor VORB_MAYBE_UNUSED /*= f32v3(1.0f)*/, const f32v3& ambient /*= f32v3(0.0f)*/) {\n    m_opaqueProgram.use();\n    glUniform3fv(m_opaqueProgram.getUniform(\"unLightDirWorld\"), 1, &(sunDir[0]));\n    glUniform1f(m_opaqueProgram.getUniform(\"unSpecularExponent\"), soaOptions.get(OPT_SPECULAR_EXPONENT).value.f);\n    glUniform1f(m_opaqueProgram.getUniform(\"unSpecularIntensity\"), soaOptions.get(OPT_SPECULAR_INTENSITY).value.f * 0.3f);\n\n    // Bind the block textures\n    glActiveTexture(GL_TEXTURE0);\n    glUniform1i(m_opaqueProgram.getUniform(\"unTextures\"), 0); // TODO(Ben): Temporary\n    glBindTexture(GL_TEXTURE_2D_ARRAY, textureAtlas);\n\n    // f32 blockAmbient = 0.000f;\n    glUniform3fv(m_opaqueProgram.getUniform(\"unAmbientLight\"), 1, &ambient[0]);\n    glUniform3fv(m_opaqueProgram.getUniform(\"unSunColor\"), 1, &sunDir[0]);\n\n    glUniform1f(m_opaqueProgram.getUniform(\"unFadeDist\"), 100000.0f/*ChunkRenderer::fadeDist*/);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sharedIBO);\n}\n\nvoid ChunkRenderer::drawOpaque(const ChunkMesh *cm, const f64v3 &PlayerPos, const f32m4 &VP) const {\n    if (cm->vaoID == 0) return;\n    \n    setMatrixTranslation(worldMatrix, f64v3(cm->position), PlayerPos);\n\n    f32m4 MVP = VP * worldMatrix;\n    glUniformMatrix4fv(m_opaqueProgram.getUniform(\"unWVP\"), 1, GL_FALSE, &MVP[0][0]);\n    glUniformMatrix4fv(m_opaqueProgram.getUniform(\"unW\"), 1, GL_FALSE, &worldMatrix[0][0]);\n\n    glBindVertexArray(cm->vaoID);\n\n    const ChunkMeshRenderData& chunkMeshInfo = cm->renderData;\n    //top\n    if (chunkMeshInfo.pyVboSize && PlayerPos.y > cm->position.y + chunkMeshInfo.lowestY) {\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.pyVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.pyVboOff * sizeof(GLuint)));\n    }\n    //front\n    if (chunkMeshInfo.pzVboSize && PlayerPos.z > cm->position.z + chunkMeshInfo.lowestZ){\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.pzVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.pzVboOff * sizeof(GLuint)));\n    }\n    //back\n    if (chunkMeshInfo.nzVboSize && PlayerPos.z < cm->position.z + chunkMeshInfo.highestZ){\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.nzVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.nzVboOff * sizeof(GLuint)));\n    }\n    //left\n    if (chunkMeshInfo.nxVboSize && PlayerPos.x < cm->position.x + chunkMeshInfo.highestX){\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.nxVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.nxVboOff * sizeof(GLuint)));\n    }\n    //right\n    if (chunkMeshInfo.pxVboSize && PlayerPos.x > cm->position.x + chunkMeshInfo.lowestX){\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.pxVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.pxVboOff * sizeof(GLuint)));\n    }\n    //bottom\n    if (chunkMeshInfo.nyVboSize && PlayerPos.y < cm->position.y + chunkMeshInfo.highestY){\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.nyVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.nyVboOff * sizeof(GLuint)));\n    }\n\n    glBindVertexArray(0);\n}\n\nvoid ChunkRenderer::drawOpaqueCustom(const ChunkMesh* cm, vg::GLProgram& m_program, const f64v3& PlayerPos, const f32m4& VP) {\n    if (cm->vaoID == 0) return;\n    \n    setMatrixTranslation(worldMatrix, f64v3(cm->position), PlayerPos);\n\n    f32m4 MVP = VP * worldMatrix;\n\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, GL_FALSE, &MVP[0][0]);\n    glUniformMatrix4fv(m_program.getUniform(\"unW\"), 1, GL_FALSE, &worldMatrix[0][0]);\n\n    glBindVertexArray(cm->vaoID);\n\n    const ChunkMeshRenderData& chunkMeshInfo = cm->renderData;\n    //top\n    if (chunkMeshInfo.pyVboSize && PlayerPos.y > cm->position.y + chunkMeshInfo.lowestY) {\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.pyVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.pyVboOff * sizeof(GLuint)));\n    }\n    //front\n    if (chunkMeshInfo.pzVboSize && PlayerPos.z > cm->position.z + chunkMeshInfo.lowestZ) {\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.pzVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.pzVboOff * sizeof(GLuint)));\n    }\n    //back\n    if (chunkMeshInfo.nzVboSize && PlayerPos.z < cm->position.z + chunkMeshInfo.highestZ) {\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.nzVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.nzVboOff * sizeof(GLuint)));\n    }\n    //left\n    if (chunkMeshInfo.nxVboSize && PlayerPos.x < cm->position.x + chunkMeshInfo.highestX) {\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.nxVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.nxVboOff * sizeof(GLuint)));\n    }\n    //right\n    if (chunkMeshInfo.pxVboSize && PlayerPos.x > cm->position.x + chunkMeshInfo.lowestX) {\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.pxVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.pxVboOff * sizeof(GLuint)));\n    }\n    //bottom\n    if (chunkMeshInfo.nyVboSize && PlayerPos.y < cm->position.y + chunkMeshInfo.highestY) {\n        glDrawElements(GL_TRIANGLES, chunkMeshInfo.nyVboSize, GL_UNSIGNED_INT, (void*)(chunkMeshInfo.nyVboOff * sizeof(GLuint)));\n    }\n\n    glBindVertexArray(0);\n}\n\n\nvoid ChunkRenderer::beginTransparent(VGTexture textureAtlas, const f32v3& sunDir, const f32v3& lightColor VORB_MAYBE_UNUSED /*= f32v3(1.0f)*/, const f32v3& ambient /*= f32v3(0.0f)*/) {\n    m_transparentProgram.use();\n    \n    glUniform3fv(m_transparentProgram.getUniform(\"unLightDirWorld\"), 1, &(sunDir[0]));\n    glUniform1f(m_transparentProgram.getUniform(\"unSpecularExponent\"), soaOptions.get(OPT_SPECULAR_EXPONENT).value.f);\n    glUniform1f(m_transparentProgram.getUniform(\"unSpecularIntensity\"), soaOptions.get(OPT_SPECULAR_INTENSITY).value.f * 0.3f);\n\n    // Bind the block textures\n    glActiveTexture(GL_TEXTURE0);\n    glUniform1i(m_transparentProgram.getUniform(\"unTextures\"), 0); // TODO(Ben): Temporary\n    glBindTexture(GL_TEXTURE_2D_ARRAY, textureAtlas);\n\n    // f32 blockAmbient = 0.000f;\n    glUniform3fv(m_transparentProgram.getUniform(\"unAmbientLight\"), 1, &ambient[0]);\n    glUniform3fv(m_transparentProgram.getUniform(\"unSunColor\"), 1, &sunDir[0]);\n\n    glUniform1f(m_transparentProgram.getUniform(\"unFadeDist\"), 100000.0f/*ChunkRenderer::fadeDist*/);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sharedIBO);\n}\n\nvoid ChunkRenderer::drawTransparent(const ChunkMesh *cm, const f64v3 &playerPos, const f32m4 &VP) const {\n    if (cm->transVaoID == 0) return;\n\n    setMatrixTranslation(worldMatrix, f64v3(cm->position), playerPos);\n\n    f32m4 MVP = VP * worldMatrix;\n\n    glUniformMatrix4fv(m_transparentProgram.getUniform(\"MVP\"), 1, GL_FALSE, &MVP[0][0]);\n    glUniformMatrix4fv(m_transparentProgram.getUniform(\"M\"), 1, GL_FALSE, &worldMatrix[0][0]);\n\n    glBindVertexArray(cm->transVaoID);\n\n    glDrawElements(GL_TRIANGLES, cm->renderData.transVboSize, GL_UNSIGNED_INT, nullptr);\n\n    glBindVertexArray(0);\n}\n\nvoid ChunkRenderer::beginCutout(VGTexture textureAtlas, const f32v3& sunDir, const f32v3& lightColor VORB_MAYBE_UNUSED /*= f32v3(1.0f)*/, const f32v3& ambient /*= f32v3(0.0f)*/) {\n    m_cutoutProgram.use();\n    glUniform3fv(m_cutoutProgram.getUniform(\"unLightDirWorld\"), 1, &(sunDir[0]));\n    glUniform1f(m_cutoutProgram.getUniform(\"unSpecularExponent\"), soaOptions.get(OPT_SPECULAR_EXPONENT).value.f);\n    glUniform1f(m_cutoutProgram.getUniform(\"unSpecularIntensity\"), soaOptions.get(OPT_SPECULAR_INTENSITY).value.f * 0.3f);\n\n    // Bind the block textures\n    glActiveTexture(GL_TEXTURE0);\n    glUniform1i(m_cutoutProgram.getUniform(\"unTextures\"), 0); // TODO(Ben): Temporary\n    glBindTexture(GL_TEXTURE_2D_ARRAY, textureAtlas);\n\n    // f32 blockAmbient = 0.000f;\n    glUniform3fv(m_cutoutProgram.getUniform(\"unAmbientLight\"), 1, &ambient[0]);\n    glUniform3fv(m_cutoutProgram.getUniform(\"unSunColor\"), 1, &sunDir[0]);\n\n    glUniform1f(m_cutoutProgram.getUniform(\"unFadeDist\"), 100000.0f/*ChunkRenderer::fadeDist*/);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sharedIBO);\n}\n\nvoid ChunkRenderer::drawCutout(const ChunkMesh *cm, const f64v3 &playerPos, const f32m4 &VP) const {\n    if (cm->cutoutVaoID == 0) return;\n\n    setMatrixTranslation(worldMatrix, f64v3(cm->position), playerPos);\n\n    f32m4 MVP = VP * worldMatrix;\n\n    glUniformMatrix4fv(m_cutoutProgram.getUniform(\"unWVP\"), 1, GL_FALSE, &MVP[0][0]);\n    glUniformMatrix4fv(m_cutoutProgram.getUniform(\"unW\"), 1, GL_FALSE, &worldMatrix[0][0]);\n\n    glBindVertexArray(cm->cutoutVaoID);\n\n    glDrawElements(GL_TRIANGLES, cm->renderData.cutoutVboSize, GL_UNSIGNED_INT, nullptr);\n\n    glBindVertexArray(0);\n}\n\nvoid ChunkRenderer::beginLiquid(VGTexture textureAtlas, const f32v3& sunDir, const f32v3& lightColor VORB_MAYBE_UNUSED /*= f32v3(1.0f)*/, const f32v3& ambient /*= f32v3(0.0f)*/) {\n    m_waterProgram.use();\n    glUniform3fv(m_waterProgram.getUniform(\"unLightDirWorld\"), 1, &(sunDir[0]));\n    glUniform1f(m_waterProgram.getUniform(\"unSpecularExponent\"), soaOptions.get(OPT_SPECULAR_EXPONENT).value.f);\n    glUniform1f(m_waterProgram.getUniform(\"unSpecularIntensity\"), soaOptions.get(OPT_SPECULAR_INTENSITY).value.f * 0.3f);\n\n    // Bind the block textures\n    glActiveTexture(GL_TEXTURE0);\n    glUniform1i(m_waterProgram.getUniform(\"unTextures\"), 0); // TODO(Ben): Temporary\n    glBindTexture(GL_TEXTURE_2D_ARRAY, textureAtlas);\n\n    // f32 blockAmbient = 0.000f;\n    glUniform3fv(m_waterProgram.getUniform(\"unAmbientLight\"), 1, &ambient[0]);\n    glUniform3fv(m_waterProgram.getUniform(\"unSunColor\"), 1, &sunDir[0]);\n\n    glUniform1f(m_waterProgram.getUniform(\"unFadeDist\"), 100000.0f/*ChunkRenderer::fadeDist*/);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sharedIBO);\n}\n\nvoid ChunkRenderer::drawLiquid(const ChunkMesh *cm, const f64v3 &PlayerPos, const f32m4 &VP) const {\n    //use drawWater bool to avoid checking frustum twice\n    if (cm->inFrustum && cm->waterVboID){\n\n        setMatrixTranslation(worldMatrix, f64v3(cm->position), PlayerPos);\n\n        f32m4 MVP = VP * worldMatrix;\n\n        glUniformMatrix4fv(m_waterProgram.getUniform(\"MVP\"), 1, GL_FALSE, &MVP[0][0]);\n        glUniformMatrix4fv(m_waterProgram.getUniform(\"M\"), 1, GL_FALSE, &worldMatrix[0][0]);\n\n        glBindVertexArray(cm->waterVaoID);\n\n        glDrawElements(GL_TRIANGLES, cm->renderData.waterIndexSize, GL_UNSIGNED_INT, 0);\n\n        glBindVertexArray(0);\n    }\n}\n\nvoid ChunkRenderer::end() {\n    vg::GLProgram::unuse();\n}\n"
  },
  {
    "path": "SoA/ChunkRenderer.h",
    "content": "#pragma once\n\n#ifndef ChunkRenderer_h__\n#define ChunkRenderer_h__\n\n#include <Vorb/graphics/GLProgram.h>\n\n#include \"ChunkMesh.h\"\n\nclass GameRenderParams;\nclass PhysicsBlockMesh;\n\n#define CHUNK_DIAGONAL_LENGTH 28.0f\n\nclass ChunkRenderer {\npublic:\n    // Loads the shaders. Call on render thread.\n    void init();\n    void dispose();\n\n    void beginOpaque(VGTexture textureAtlas, const f32v3& sunDir, const f32v3& lightColor = f32v3(1.0f), const f32v3& ambient = f32v3(0.0f));\n    void drawOpaque(const ChunkMesh* cm, const f64v3& PlayerPos, const f32m4& VP) const;\n    static void drawOpaqueCustom(const ChunkMesh* cm, vg::GLProgram& m_program, const f64v3& PlayerPos, const f32m4& VP);\n\n    void beginTransparent(VGTexture textureAtlas, const f32v3& sunDir, const f32v3& lightColor = f32v3(1.0f), const f32v3& ambient = f32v3(0.0f));\n    void drawTransparent(const ChunkMesh* cm, const f64v3& playerPos, const f32m4& VP) const;\n    \n    void beginCutout(VGTexture textureAtlas, const f32v3& sunDir, const f32v3& lightColor = f32v3(1.0f), const f32v3& ambient = f32v3(0.0f));\n    void drawCutout(const ChunkMesh* cm, const f64v3& playerPos, const f32m4& VP) const;\n\n    void beginLiquid(VGTexture textureAtlas, const f32v3& sunDir, const f32v3& lightColor = f32v3(1.0f), const f32v3& ambient = f32v3(0.0f));\n    void drawLiquid(const ChunkMesh* cm, const f64v3& PlayerPos, const f32m4& VP) const;\n\n    // Unbinds the shader\n    static void end();\n\n    static volatile f32 fadeDist;\n    static VGIndexBuffer sharedIBO;\nprivate:\n    static f32m4 worldMatrix; ///< Reusable world matrix for chunks\n    vg::GLProgram m_opaqueProgram;\n    vg::GLProgram m_transparentProgram;\n    vg::GLProgram m_cutoutProgram;\n    vg::GLProgram m_waterProgram;\n};\n\n#endif // ChunkRenderer_h__\n"
  },
  {
    "path": "SoA/ChunkSphereComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkSphereComponentUpdater.h\"\n\n#include \"ChunkAccessor.h\"\n#include \"ChunkID.h\"\n#include \"GameSystem.h\"\n#include \"SpaceSystem.h\"\n#include \"VoxelSpaceConversions.h\"\n#include \"soaUtils.h\"\n\n#define X_AXIS 0\n#define Y_AXIS 1\n#define Z_AXIS 2\n\nvoid ChunkSphereComponentUpdater::update(GameSystem* gameSystem, SpaceSystem* spaceSystem) {\n    for (auto& it : gameSystem->chunkSphere) {\n        ChunkSphereComponent& cmp = it.second;\n        auto& voxelPos = gameSystem->voxelPosition.get(cmp.voxelPosition);\n        ChunkPosition3D chunkPos = VoxelSpaceConversions::voxelToChunk(voxelPos.gridPosition);\n\n        // Check for grid shift or init\n        if (cmp.currentCubeFace != chunkPos.face) {\n            releaseHandles(cmp);\n            cmp.centerPosition = chunkPos;\n            cmp.currentCubeFace = chunkPos.face;\n            auto& sphericalVoxel = spaceSystem->sphericalVoxel.get(voxelPos.parentVoxel);\n            cmp.chunkGrid = &sphericalVoxel.chunkGrids[chunkPos.face];\n            initSphere(cmp);\n        }\n\n        // Check for shift\n        if (chunkPos.pos != cmp.centerPosition) {\n            i32v3 offset = chunkPos.pos - cmp.centerPosition;\n\n            i32 dx2 = offset.x * offset.x;\n            i32 dy2 = offset.y * offset.y;\n            i32 dz2 = offset.z * offset.z;\n            if (dx2 + dy2 + dz2 == 1) {\n                // Hideous but fast version. Shift by 1.\n                if (dx2) {\n                    shiftDirection(cmp, X_AXIS, Y_AXIS, Z_AXIS, offset.x);\n                } else if (dz2) {\n                    shiftDirection(cmp, Z_AXIS, Y_AXIS, X_AXIS, offset.z);\n                } else {\n                    shiftDirection(cmp, Y_AXIS, X_AXIS, Z_AXIS, offset.y);\n                }\n                cmp.centerPosition = chunkPos.pos;\n            } else {\n                // Slow version. Multi-chunk shift.\n                cmp.offset += chunkPos.pos - cmp.centerPosition;\n                // Scale back to the range\n                for (int i = 0; i < 3; i++) {\n                    while (cmp.offset[i] > cmp.radius) cmp.offset[i] -= cmp.width;\n                    while (cmp.offset[i] < -cmp.radius) cmp.offset[i] += cmp.width;\n                }\n                cmp.centerPosition = chunkPos.pos;\n                int radius2 = cmp.radius * cmp.radius;\n\n                // Get all in range slots\n                for (int y = -cmp.radius; y <= cmp.radius; y++) {\n                    for (int z = -cmp.radius; z <= cmp.radius; z++) {\n                        for (int x = -cmp.radius; x <= cmp.radius; x++) {\n                            i32v3 p = cmp.offset + i32v3(x, y, z);\n                            // Wrap (I hope this gets optimized)\n                            for (int i = 0; i < 3; i++) {\n                                if (p[i] < -cmp.radius) {\n                                    p[i] += cmp.width;\n                                } else if (p[i] > cmp.radius) {\n                                    p[i] -= cmp.width;\n                                }\n                            }\n\n                            int index = (p.y + cmp.radius) * cmp.layer + (p.z + cmp.radius) * cmp.width + (p.x + cmp.radius);\n                            if (cmp.handleGrid[index].isAquired()) {\n                                i32v3 diff = cmp.handleGrid[index]->getChunkPosition().pos - cmp.centerPosition;\n                                int d2 = selfDot(diff);\n                                if (d2 <= radius2) {\n                                    continue; // Still in range\n                                } else {\n                                    releaseAndDisconnect(cmp, cmp.handleGrid[index]);\n                                }\n                            }\n                            // Check if its in range\n                            if (x * x + y * y + z * z <= radius2) {\n                                i32v3 chunkPos(cmp.centerPosition.x + x,\n                                               cmp.centerPosition.y + y,\n                                               cmp.centerPosition.z + z);\n                                // TODO(Ben): Sort\n                                cmp.handleGrid[index] = submitAndConnect(cmp, chunkPos);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid ChunkSphereComponentUpdater::setRadius(ChunkSphereComponent& cmp, ui32 radius) {\n    // Release old handles\n    releaseHandles(cmp);\n\n    // Set vars\n    cmp.radius = radius;\n    cmp.width = cmp.radius * 2 + 1;\n    cmp.layer = cmp.width * cmp.width;\n    cmp.size = cmp.layer * cmp.width;\n\n    // Allocate handles\n    initSphere(cmp);\n}\n\n#define GET_INDEX(x, y, z) (((x) + cmp.radius) + ((y) + cmp.radius) * cmp.layer + ((z) + cmp.radius) * cmp.width)\n\nvoid ChunkSphereComponentUpdater::shiftDirection(ChunkSphereComponent& cmp, int axis1, int axis2, int axis3, int offset) {\n    if (offset > 0) {\n        // Release\n        for (auto& o : cmp.acquireOffsets) {\n            i32v3 p;\n            p[axis1] = cmp.offset[axis1] - o.x + 1;\n            p[axis2] = cmp.offset[axis2] + o.y;\n            p[axis3] = cmp.offset[axis3] + o.z;\n            // Wrap (I hope this gets optimized)\n            for (int i = 0; i < 3; i++) {\n                if (p[i] < -cmp.radius) {\n                    p[i] += cmp.width;\n                } else if (p[i] > cmp.radius) {\n                    p[i] -= cmp.width;\n                }\n            }\n            releaseAndDisconnect(cmp, cmp.handleGrid[GET_INDEX(p.x, p.y, p.z)]);\n        }\n        // Acquire\n        for (auto& o : cmp.acquireOffsets) {\n            i32v3 p;\n            p[axis1] = cmp.offset[axis1] + o.x;\n            p[axis2] = cmp.offset[axis2] + o.y;\n            p[axis3] = cmp.offset[axis3] + o.z;\n            // Wrap (I hope this gets optimized)\n            for (int i = 0; i < 3; i++) {\n                if (p[i] < -cmp.radius) {\n                    p[i] += cmp.width;\n                } else if (p[i] > cmp.radius) {\n                    p[i] -= cmp.width;\n                }\n            }\n            i32v3 off;\n            off[axis1] = o.x;\n            off[axis2] = o.y;\n            off[axis3] = o.z;\n            cmp.handleGrid[GET_INDEX(p.x, p.y, p.z)] = submitAndConnect(cmp, cmp.centerPosition + off);\n        }\n\n        cmp.offset[axis1]++;\n        if (cmp.offset[axis1] > cmp.radius) cmp.offset[axis1] = -cmp.radius;\n    } else {\n        for (auto& o : cmp.acquireOffsets) {\n            i32v3 p;\n            p[axis1] = cmp.offset[axis1] + o.x - 1;\n            p[axis2] = cmp.offset[axis2] + o.y;\n            p[axis3] = cmp.offset[axis3] + o.z;\n            // Wrap (I hope this gets optimized)\n            for (int i = 0; i < 3; i++) {\n                if (p[i] < -cmp.radius) {\n                    p[i] += cmp.width;\n                } else if (p[i] > cmp.radius) {\n                    p[i] -= cmp.width;\n                }\n            }\n            releaseAndDisconnect(cmp, cmp.handleGrid[GET_INDEX(p.x, p.y, p.z)]);\n        }\n        // Acquire\n        for (auto& o : cmp.acquireOffsets) {\n            i32v3 p;\n            p[axis1] = cmp.offset[axis1] - o.x;\n            p[axis2] = cmp.offset[axis2] + o.y;\n            p[axis3] = cmp.offset[axis3] + o.z;\n            // Wrap (I hope this gets optimized)\n            for (int i = 0; i < 3; i++) {\n                if (p[i] < -cmp.radius) {\n                    p[i] += cmp.width;\n                } else if (p[i] > cmp.radius) {\n                    p[i] -= cmp.width;\n                }\n            }\n            i32v3 off;\n            off[axis1] = -o.x;\n            off[axis2] = o.y;\n            off[axis3] = o.z;\n            cmp.handleGrid[GET_INDEX(p.x, p.y, p.z)] = submitAndConnect(cmp, cmp.centerPosition + off);\n        }\n\n        cmp.offset[axis1]--;\n        if (cmp.offset[axis1] < -cmp.radius) cmp.offset[axis1] = cmp.radius;\n    }\n}\n\n#undef GET_INDEX\n\nChunkHandle ChunkSphereComponentUpdater::submitAndConnect(ChunkSphereComponent& cmp, const i32v3& chunkPos) {\n    ChunkHandle h = cmp.chunkGrid->submitQuery(chunkPos, GEN_DONE, true)->chunk.acquire();\n    // TODO(Ben): meshableNeighbors\n    // Acquire the 26 neighbors\n    // TODO(Ben): Could optimize\n    ChunkAccessor& accessor = cmp.chunkGrid->accessor;\n    { // Left\n        ChunkID id = h.getID();\n        id.x--;\n        h->neighbor.left = accessor.acquire(id);\n    }\n    { // Right\n        ChunkID id = h.getID();\n        id.x++;\n        h->neighbor.right = accessor.acquire(id);\n    }\n    { // Bottom\n        ChunkID id = h.getID();\n        id.y--;\n        h->neighbor.bottom = accessor.acquire(id);\n    }\n    { // Top\n        ChunkID id = h.getID();\n        id.y++;\n        h->neighbor.top = accessor.acquire(id);\n    }\n    { // Back\n        ChunkID id = h.getID();\n        id.z--;\n        h->neighbor.back = accessor.acquire(id);\n    }\n    { // Front\n        ChunkID id = h.getID();\n        id.z++;\n        h->neighbor.front = accessor.acquire(id);\n    }\n    cmp.chunkGrid->onNeighborsAcquire(h);\n    return h;\n\n#undef GET_HALF\n}\n\nvoid ChunkSphereComponentUpdater::releaseAndDisconnect(ChunkSphereComponent& cmp, ChunkHandle& h) {\n    // Call the event first to prevent race condition\n    cmp.chunkGrid->onNeighborsRelease(h);\n    h->neighbor.left.release();\n    h->neighbor.right.release();\n    h->neighbor.back.release();\n    h->neighbor.front.release();\n    h->neighbor.bottom.release();\n    h->neighbor.top.release();\n    h.release();\n}\n\nvoid ChunkSphereComponentUpdater::releaseHandles(ChunkSphereComponent& cmp) {\n    if (cmp.handleGrid) {\n        for (int i = 0; i < cmp.size; i++) {\n            if (cmp.handleGrid[i].isAquired()) releaseAndDisconnect(cmp, cmp.handleGrid[i]);\n        }\n        delete[] cmp.handleGrid;\n        cmp.handleGrid = nullptr;\n    }\n}\n\nvoid ChunkSphereComponentUpdater::initSphere(ChunkSphereComponent& cmp) {\n    cmp.handleGrid = new ChunkHandle[cmp.size];\n    cmp.offset = i32v3(0);\n\n    // Pre-compute offsets\n    int radius2 = cmp.radius * cmp.radius;\n\n    // Get all in range slots\n    for (int y = -cmp.radius; y <= cmp.radius; y++) {\n        for (int z = -cmp.radius; z <= cmp.radius; z++) {\n            for (int x = -cmp.radius; x <= cmp.radius; x++) {\n                // Check if its in range\n                if (x * x + y * y + z * z <= radius2) {\n                    int index = (y + cmp.radius) * cmp.layer + (z + cmp.radius) * cmp.width + (x + cmp.radius);\n                    i32v3 chunkPos(cmp.centerPosition.x + x,\n                                   cmp.centerPosition.y + y,\n                                   cmp.centerPosition.z + z);\n                    // TODO(Ben): Sort\n                    cmp.handleGrid[index] = submitAndConnect(cmp, chunkPos);\n                }\n            }\n        }\n    }\n    // Determine +x acquire offsets\n    int index = 0;\n    for (int y = -cmp.radius; y <= cmp.radius; y++) {\n        for (int z = -cmp.radius; z <= cmp.radius; z++) {\n            for (int x = -cmp.radius; x <= cmp.radius; x++, index++) {\n                if (cmp.handleGrid[index].isAquired()) {\n                    if (x == cmp.radius || !cmp.handleGrid[index + 1].isAquired()) {\n                        cmp.acquireOffsets.emplace_back(x + 1, y, z);\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "SoA/ChunkSphereComponentUpdater.h",
    "content": "//\n// ChunkSphereAcquirer.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 8 Aug 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Acquires a sphere of chunks around an agent.\n//\n\n#pragma once\n\n#ifndef ChunkSphereAcquirer_h__\n#define ChunkSphereAcquirer_h__\n\n#include \"ChunkHandle.h\"\n#include \"GameSystemComponents.h\"\n\nclass GameSystem;\nclass SpaceSystem;\nclass ChunkAccessor;\n\nclass ChunkSphereComponentUpdater {\npublic:\n    void update(GameSystem* gameSystem, SpaceSystem* spaceSystem);\n\n    void setRadius(ChunkSphereComponent& cmp, ui32 radius);\n\nprivate:\n    void shiftDirection(ChunkSphereComponent& cmp, int axis1, int axis2, int axis3, int offset);\n    // Submits a gen query and connects to neighbors\n    ChunkHandle submitAndConnect(ChunkSphereComponent& cmp, const i32v3& chunkPos);\n    void releaseAndDisconnect(ChunkSphereComponent& cmp, ChunkHandle& h);\n    void releaseHandles(ChunkSphereComponent& cmp);\n    void initSphere(ChunkSphereComponent& cmp);\n};\n\n#endif // ChunkSphereAcquirer_h__\n"
  },
  {
    "path": "SoA/ChunkUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ChunkUpdater.h\"\n\n#include \"BlockPack.h\"\n#include \"CAEngine.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"VoxelLightEngine.h\"\n#include \"VoxelNavigation.inl\"\n#include \"VoxelUtils.h\"\n\n#include \"VoxelUpdateOrder.inl\"\n\nBlockPack* ChunkUpdater::blockPack = nullptr;\n\nvoid ChunkUpdater::randomBlockUpdates(PhysicsEngine* physicsEngine VORB_UNUSED, Chunk* chunk VORB_UNUSED)\n{\n    //if (!chunk->isAccessible) return;\n    //int blockIndex, blockIndex2, blockID;\n    //ChunkStates newState;\n    //bool needsSetup;\n    //Chunk *owner;\n\n    //Chunk* left = chunk->left;\n    //Chunk* right = chunk->right;\n    //Chunk* front = chunk->front;\n    //Chunk* back = chunk->back;\n    //Chunk* bottom = chunk->bottom;\n    //Chunk* top = chunk->top;\n\n    //i32v3 pos;\n\n    //Chunk* lockedChunk = nullptr;\n\n    //for (int i = 0; i < 15; i++) {\n    //    needsSetup = false;\n\n    //    blockIndex = RandomUpdateOrder[chunk->blockUpdateIndex++];\n    //    if (chunk->blockUpdateIndex == CHUNK_SIZE) chunk->blockUpdateIndex = 0;\n\n    //    pos = getPosFromBlockIndex(blockIndex);\n    //    \n    //    blockID = chunk->getBlockIDSafe(lockedChunk, blockIndex);\n\n    //    if (Blocks[blockID].emitterRandom){\n    //        // uncomment for falling leaves\n    //        //    particleEngine.AddAnimatedParticles(1, f64v3(position.x + x, Y + y, position.z + z), Blocks[b].emitterRandom);\n    //    }\n\n    //    //TODO: Replace most of this with block update scripts\n    //    //TODO(Ben): There are race conditions here!\n    //    if (blockID >= LOWWATER && blockID < LOWWATER + 5 && (GETBLOCKID(vvox::getBottomBlockData(chunk, lockedChunk, blockIndex, pos.y, blockIndex2, owner)) < LOWWATER)) {\n    //        chunk->setBlockDataSafe(lockedChunk, blockIndex, NONE);\n    //        owner->numBlocks--;\n    //        needsSetup = true;\n    //        newState = ChunkStates::WATERMESH;\n    //        ChunkUpdater::addBlockToUpdateList(chunk, lockedChunk, blockIndex);\n    //    } else if (blockID == FIRE) {\n    //        // TODO(Ben): Update\n    //        //updateFireBlock(chunkManager, physicsEngine, chunk, blockIndex);\n    //        needsSetup = true;\n    //        newState = ChunkStates::MESH;\n    //    } else if (blockID == DIRTGRASS){\n    //        ui32 bt = GETBLOCKID(vvox::getTopBlockData(chunk, lockedChunk, blockIndex, pos.y, blockIndex2, owner));\n    //        // Tmp debugging           \n    //        if (bt > Blocks.size()) {\n    //            pError(\"Invalid block in update!: \" + std::to_string(bt));\n    //        }\n    //        if ((Blocks[bt].collide && bt != LEAVES1) || bt >= LOWWATER){\n    //            chunk->setBlockDataSafe(lockedChunk, blockIndex, DIRT);\n    //            needsSetup = true;\n    //            newState = ChunkStates::MESH;\n    //        }\n    //    } else if (blockID == DIRT){\n    //        if ((rand() % 10 == 0) && (GETBLOCKID(vvox::getTopBlockData(chunk, lockedChunk, blockIndex, pos.y, blockIndex2, owner)) == NONE) &&\n    //            (GETBLOCKID(vvox::getLeftBlockData(chunk, lockedChunk, blockIndex, pos.x, blockIndex2, owner)) == DIRTGRASS ||\n    //            GETBLOCKID(vvox::getRightBlockData(chunk, lockedChunk, blockIndex, pos.x, blockIndex2, owner)) == DIRTGRASS ||\n    //            GETBLOCKID(vvox::getFrontBlockData(chunk, lockedChunk, blockIndex, pos.z, blockIndex2, owner)) == DIRTGRASS ||\n    //            GETBLOCKID(vvox::getBackBlockData(chunk, lockedChunk, blockIndex, pos.z, blockIndex2, owner)) == DIRTGRASS)) {\n    //            chunk->setBlockDataSafe(lockedChunk, blockIndex, DIRTGRASS);\n    //            needsSetup = true;\n    //            newState = ChunkStates::MESH;\n    //        }\n    //    }\n\n    //    if (needsSetup){\n    //        \n    //        chunk->changeState(newState);\n    //        if (pos.x == 0){\n    //            if (left && left->isAccessible){\n    //                left->changeState(newState);\n    //            }\n    //        } else if (pos.x == CHUNK_WIDTH - 1){\n    //            if (right && right->isAccessible){\n    //                right->changeState(newState);\n    //            }\n    //        }\n    //        if (pos.y == 0){\n    //            if (bottom && bottom->isAccessible){\n    //                bottom->changeState(newState);\n    //            }\n    //        } else if (pos.y == CHUNK_WIDTH - 1){\n    //            if (top && top->isAccessible){\n    //                top->changeState(newState);\n    //            }\n    //        }\n    //        if (pos.z == 0){\n    //            if (back && back->isAccessible){\n    //                back->changeState(newState);\n    //            }\n    //        } else if (pos.z == CHUNK_WIDTH - 1){\n    //            if (front && front->isAccessible){\n    //                front->changeState(newState);\n    //            }\n    //        }\n    //    }\n    //}\n    //if (lockedChunk) lockedChunk->unlock();\n}\n\nvoid ChunkUpdater::placeBlockSafe(Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, BlockIndex blockIndex VORB_UNUSED, BlockID blockData VORB_UNUSED) {\n   /* vvox::swapLockedChunk(chunk, lockedChunk);\n    placeBlock(chunk, lockedChunk, blockIndex, blockData);*/\n}\n\nvoid ChunkUpdater::placeBlockNoUpdate(Chunk* chunk, BlockIndex blockIndex, BlockID blockType) {\n \n    chunk->blocks.set(blockIndex, blockType);\n    chunk->flagDirty();\n\n    //Block &block = GETBLOCK(blockType);\n\n    //if (chunk->getBlockData(blockIndex) == NONE) {\n    //    chunk->numBlocks++;\n    //}\n    //chunk->setBlockData(blockIndex, blockType);\n\n    //if (block.spawnerVal || block.sinkVal) {\n    //    chunk->spawnerBlocks.push_back(blockIndex);\n    //}\n\n    //const i32v3 pos = getPosFromBlockIndex(blockIndex);\n\n    //if (block.emitter) {\n    //    particleEngine.addEmitter(block.emitter, f64v3(chunk->voxelPosition.x + pos.x, chunk->voxelPosition.y + pos.y, chunk->voxelPosition.z + pos.z), blockType);\n    //}\n\n    //// If its a plant, we need to do some extra iteration\n    //if (block.floraHeight) {\n    //    placeFlora(chunk, blockIndex, blockType);\n    //}\n\n    ////Check for light removal due to block occlusion\n    //if (block.blockLight) {\n\n    //    if (chunk->getSunlight(blockIndex)) {\n    //        if (chunk->getSunlight(blockIndex) == MAXLIGHT) {\n    //            chunk->setSunlight(blockIndex, 0);\n    //            chunk->sunRemovalList.push_back(blockIndex);\n    //        } else {\n    //            chunk->sunlightRemovalQueue.emplace(blockIndex, chunk->getSunlight(blockIndex));\n    //            chunk->setSunlight(blockIndex, 0);\n    //        }\n    //    }\n\n    //    if (chunk->getLampLight(blockIndex)) {\n    //        chunk->lampLightRemovalQueue.emplace(blockIndex, chunk->getLampLight(blockIndex));\n    //        chunk->setLampLight(blockIndex, 0);\n    //    }\n    //} else if (block.colorFilter != f32v3(1.0f)) {\n    //    //This will pull light from neighbors\n    //    chunk->lampLightRemovalQueue.emplace(blockIndex, chunk->getLampLight(blockIndex));\n    //    chunk->setLampLight(blockIndex, 0);\n    //}\n    ////Light placement\n    //if (block.lightColorPacked) {\n    //    chunk->setLampLight(blockIndex, block.lightColorPacked);\n    //    chunk->lampLightUpdateQueue.emplace(blockIndex, block.lightColorPacked);\n    //}\n\n    //if (GETBLOCKID(blockType) >= LOWWATER) {\n    //    chunk->changeState(ChunkStates::WATERMESH);\n    //    updateNeighborStates(chunk, pos, ChunkStates::WATERMESH);\n    //} else {\n    //    chunk->changeState(ChunkStates::MESH);\n    //    updateNeighborStates(chunk, pos, ChunkStates::MESH);\n\n    //}\n    //chunk->dirty = true;\n}\n\n//Simplified placeBlock for liquid physics\nvoid ChunkUpdater::placeBlockFromLiquidPhysics(Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED, int blockType VORB_UNUSED)\n{\n    //Block &block = GETBLOCK(blockType);\n\n    //if (chunk->getBlockData(blockIndex) == NONE) {\n    //    chunk->numBlocks++;\n    //}\n    //chunk->setBlockData(blockIndex, blockType);\n\n    ////Check for light removal due to block occlusion\n    //if (block.blockLight) {\n\n    //    if (chunk->getSunlight(blockIndex)){\n    //        if (chunk->getSunlight(blockIndex) == MAXLIGHT){\n    //            chunk->setSunlight(blockIndex, 0);\n    //            chunk->sunRemovalList.push_back(blockIndex);\n    //        } else {\n    //            chunk->sunlightRemovalQueue.emplace(blockIndex, chunk->getSunlight(blockIndex));\n    //            chunk->setSunlight(blockIndex, 0);\n    //        }\n    //    }\n\n    //    if (chunk->getLampLight(blockIndex)){\n    //        chunk->lampLightRemovalQueue.emplace(blockIndex, chunk->getLampLight(blockIndex));\n    //        chunk->setLampLight(blockIndex, 0);\n    //    }\n    //}\n\n    ////Light placement\n    //if (block.lightColorPacked) {\n    //    chunk->setLampLight(blockIndex, block.lightColorPacked);\n    //    chunk->lampLightUpdateQueue.emplace(blockIndex, block.lightColorPacked);\n    //}\n\n    //ChunkUpdater::addBlockToUpdateList(chunk, lockedChunk, blockIndex);\n  \n    //chunk->dirty = true;\n}\n\nvoid ChunkUpdater::placeBlockFromLiquidPhysicsSafe(Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED, int blockType VORB_UNUSED) {\n    /*  vvox::swapLockedChunk(chunk, lockedChunk);\n      placeBlockFromLiquidPhysics(chunk, lockedChunk, blockIndex, blockType);*/\n}\n\nvoid ChunkUpdater::removeBlock(ChunkManager* chunkManager VORB_UNUSED, PhysicsEngine* physicsEngine VORB_UNUSED, Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED, bool isBreak VORB_UNUSED, double force VORB_UNUSED, f32v3 explodeDir VORB_UNUSED)\n{\n    //int blockID = chunk->getBlockID(blockIndex);\n    //const Block &block = Blocks[blockID];\n\n    //float explodeDist = vmath::length(explodeDir);\n\n    //const i32v3 pos = getPosFromBlockIndex(blockIndex);\n\n    //if (chunk->getBlockID(blockIndex) == 0) return;\n\n    //GLbyte da, db, dc;\n\n    ////Falling check\n    //if (explodeDist){\n    //    GLubyte d;\n    //    da = (GLbyte)(explodeDir.x);\n    //    db = (GLbyte)(explodeDir.y);\n    //    dc = (GLbyte)(explodeDir.z);\n    //    if (explodeDist > 255){\n    //        d = 255;\n    //    } else{\n    //        d = (GLubyte)(explodeDist);\n    //    }\n    //    physicsEngine->addFallingCheckNode(FallingCheckNode(chunk, blockIndex, da, db, dc, d));\n    //} else{\n    //    physicsEngine->addFallingCheckNode(FallingCheckNode(chunk, blockIndex));\n    //}\n\n    ////If we are braking the block rather than removing it, it should explode or emit particles\n    //if (isBreak) {\n    //    if (block.explosivePower){\n    //        f64v3 dtmp(chunk->voxelPosition.x + pos.x, chunk->voxelPosition.y + pos.y, chunk->voxelPosition.z + pos.z);\n    //        physicsEngine->addExplosion(ExplosionNode(dtmp, blockID));\n    //    }\n\n    //    if (block.emitterOnBreak && block.explosivePower == 0){ // \n    //        particleEngine.addEmitter(block.emitterOnBreak, f64v3(chunk->voxelPosition.x + blockIndex%CHUNK_WIDTH, chunk->voxelPosition.y + blockIndex / CHUNK_LAYER, chunk->voxelPosition.z + (blockIndex%CHUNK_LAYER) / CHUNK_WIDTH), blockID);\n    //    }\n    //    if (explodeDist){\n    //        f32 expForce = vmath::length(explodeDir);\n    //        expForce = pow(0.89f, expForce)*0.6f;\n    //        if (expForce < 0.0f) expForce = 0.0f;\n    //        breakBlock(chunk, pos.x, pos.y, pos.z, blockID, force, -vmath::normalize(explodeDir)*expForce);\n    //    } else{\n    //        breakBlock(chunk, pos.x, pos.y, pos.z, blockID, force);\n    //    }\n    //}\n    //chunk->setBlockData(blockIndex, NONE);\n\n    ////Update lighting\n    //if (block.blockLight || block.lightColorPacked) {\n    //    //This will pull light from neighbors\n    //    chunk->lampLightRemovalQueue.emplace(blockIndex, chunk->getLampLight(blockIndex));\n    //    chunk->setLampLight(blockIndex, 0);\n\n    //    //sunlight update\n    //    if (pos.y < CHUNK_WIDTH - 1) {\n    //        if (chunk->getSunlight(blockIndex + CHUNK_LAYER) == MAXLIGHT) {\n    //            chunk->setSunlight(blockIndex, MAXLIGHT);\n    //            chunk->sunExtendList.push_back(blockIndex);\n    //        } else {\n    //            //This will pull light from neighbors\n    //            chunk->sunlightRemovalQueue.emplace(blockIndex, chunk->getSunlight(blockIndex));\n    //            chunk->setSunlight(blockIndex, 0);\n    //        }\n    //    } else if (chunk->top && chunk->top->isAccessible) {\n    //        if (chunk->top->getSunlight(blockIndex + CHUNK_LAYER - CHUNK_SIZE) == MAXLIGHT) {\n    //            chunk->setSunlight(blockIndex, MAXLIGHT);\n    //            chunk->sunExtendList.push_back(blockIndex);\n    //        } else {\n    //            //This will pull light from neighbors\n    //            chunk->sunlightRemovalQueue.emplace(blockIndex, chunk->getSunlight(blockIndex));\n    //            chunk->setSunlight(blockIndex, 0);\n    //        }\n    //    } else {\n    //        //This will pull light from neighbors\n    //        chunk->sunlightRemovalQueue.emplace(blockIndex, chunk->getSunlight(blockIndex));\n    //        chunk->setSunlight(blockIndex, 0);\n    //    }\n    //}\n\n    //// If its a plant, we need to do some extra iteration\n    //if (block.floraHeight) {\n    //    removeFlora(chunkManager, physicsEngine, chunk, lockedChunk, blockIndex, blockID);\n    //}\n\n    //ChunkUpdater::addBlockToUpdateList(chunk, lockedChunk, blockIndex);\n    //chunk->numBlocks--;\n    //if (chunk->numBlocks < 0) chunk->numBlocks = 0;\n\n\n    //chunk->changeState(ChunkStates::MESH);\n    //chunk->dirty = 1;\n\n    //updateNeighborStates(chunk, pos, ChunkStates::MESH);\n}\n\nvoid ChunkUpdater::removeBlockSafe(ChunkManager* chunkManager VORB_UNUSED, PhysicsEngine* physicsEngine VORB_UNUSED, Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED, bool isBreak VORB_UNUSED, double force VORB_UNUSED, f32v3 explodeDir VORB_UNUSED) {\n    /* vvox::swapLockedChunk(chunk, lockedChunk);\n     removeBlock(chunkManager, physicsEngine, chunk, lockedChunk, blockIndex, isBreak, force, explodeDir);*/\n}\n\nvoid ChunkUpdater::removeBlockFromLiquidPhysics(Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED)\n{\n    //const Block &block = chunk->getBlock(blockIndex);\n\n    //const i32v3 pos = getPosFromBlockIndex(blockIndex);\n  \n    //chunk->setBlockData(blockIndex, NONE);\n\n    ////Update lighting\n    //if (block.blockLight || block.lightColorPacked) {\n    //    //This will pull light from neighbors\n    //    chunk->lampLightRemovalQueue.emplace(blockIndex, chunk->getLampLight(blockIndex));\n    //    chunk->setLampLight(blockIndex, 0);\n\n    //    //sunlight update\n    //    if (pos.y < CHUNK_WIDTH - 1) {\n    //        if (chunk->getSunlight(blockIndex + CHUNK_LAYER) == MAXLIGHT) {\n    //            chunk->setSunlight(blockIndex, MAXLIGHT);\n    //            chunk->sunExtendList.push_back(blockIndex);\n    //        } else {\n    //            //This will pull light from neighbors\n    //            chunk->sunlightRemovalQueue.emplace(blockIndex, chunk->getSunlight(blockIndex));\n    //            chunk->setSunlight(blockIndex, 0);\n    //        }\n    //    } else if (chunk->top && chunk->top->isAccessible) {\n    //        if (chunk->top->getSunlight(blockIndex + CHUNK_LAYER - CHUNK_SIZE) == MAXLIGHT) {\n    //            chunk->setSunlight(blockIndex, MAXLIGHT);\n    //            chunk->sunExtendList.push_back(blockIndex);\n    //        } else {\n    //            //This will pull light from neighbors\n    //            chunk->sunlightRemovalQueue.emplace(blockIndex, chunk->getSunlight(blockIndex));\n    //            chunk->setSunlight(blockIndex, 0);\n    //        }\n    //    } else {\n    //        //This will pull light from neighbors\n    //        chunk->sunlightRemovalQueue.emplace(blockIndex, chunk->getSunlight(blockIndex));\n    //        chunk->setSunlight(blockIndex, 0);\n    //    }\n    //}\n\n    //ChunkUpdater::addBlockToUpdateList(chunk, lockedChunk, blockIndex);\n    //chunk->numBlocks--;\n    //if (chunk->numBlocks < 0) chunk->numBlocks = 0;\n\n\n    //chunk->changeState(ChunkStates::WATERMESH);\n    //chunk->dirty = 1;\n}\n\nvoid ChunkUpdater::removeBlockFromLiquidPhysicsSafe(Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED) {\n   /* vvox::swapLockedChunk(chunk, lockedChunk);\n    removeBlockFromLiquidPhysics(chunk, lockedChunk, blockIndex);*/\n}\n\nvoid ChunkUpdater::updateNeighborStates(Chunk* chunk VORB_UNUSED, const i32v3& pos VORB_UNUSED, ChunkStates state VORB_UNUSED) {\n  /*  if (pos.x == 0){\n        if (chunk->left){\n            chunk->left->changeState(state);\n        }\n    } else if (pos.x == CHUNK_WIDTH - 1){\n        if (chunk->right){\n            chunk->right->changeState(state);\n        }\n    }\n    if (pos.y == 0){\n        if (chunk->bottom){\n            chunk->bottom->changeState(state);\n        }\n    } else if (pos.y == CHUNK_WIDTH - 1){\n        if (chunk->top){\n            chunk->top->changeState(state);\n        }\n    }\n    if (pos.z == 0){\n        if (chunk->back){\n            chunk->back->changeState(state);\n        }\n    } else if (pos.z == CHUNK_WIDTH - 1){\n        if (chunk->front){\n            chunk->front->changeState(state);\n        }\n    }*/\n}\n\nvoid ChunkUpdater::updateNeighborStates(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ChunkStates state VORB_UNUSED) {\n   /* const i32v3 pos = getPosFromBlockIndex(blockIndex);\n    if (pos.x == 0){\n        if (chunk->left){\n            chunk->left->changeState(state);\n        }\n    } else if (pos.x == CHUNK_WIDTH - 1){\n        if (chunk->right){\n            chunk->right->changeState(state);\n        }\n    }\n    if (pos.y == 0){\n        if (chunk->bottom){\n            chunk->bottom->changeState(state);\n        }\n    } else if (pos.y == CHUNK_WIDTH - 1){\n        if (chunk->top){\n            chunk->top->changeState(state);\n        }\n    }\n    if (pos.z == 0){\n        if (chunk->back){\n            chunk->back->changeState(state);\n        }\n    } else if (pos.z == CHUNK_WIDTH - 1){\n        if (chunk->front){\n            chunk->front->changeState(state);\n        }\n    }*/\n}\n\nvoid ChunkUpdater::updateBlockAndNeighbors(VoxelUpdateBufferer& bufferer VORB_UNUSED, Chunk* chunk VORB_UNUSED, BlockIndex index VORB_UNUSED) {\n    throw 33;\n}\n\nvoid ChunkUpdater::updateBlockAndNeighbors(VoxelUpdateBufferer& bufferer VORB_UNUSED, Chunk* chunk VORB_UNUSED, BlockIndex index VORB_UNUSED, BlockID id VORB_UNUSED)\n{\n    // int phys;\n    // TODO(Matthew): This statement wasn't used, revisit this function to make sure it is behaving correctly.\n    //const i32v3 pos = getPosFromBlockIndex(id);\n\n    // ChunkHandle& left = chunk->neighbor.left;\n    // ChunkHandle& right = chunk->neighbor.right;\n    // ChunkHandle& front = chunk->neighbor.front;\n    // ChunkHandle& back = chunk->neighbor.back;\n    // ChunkHandle& top = chunk->neighbor.top;\n    // ChunkHandle& bottom = chunk->neighbor.bottom;\n\n\n    //if ((phys = chunk->getBlockSafe(lockedChunk, c).caIndex) > -1) {\n    //    chunk->addPhysicsUpdate(phys, c);\n    //}\n\n    //if (pos.x > 0){ //left\n    //    if ((phys = chunk->getBlockSafe(lockedChunk, c - 1).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, c - 1);\n    //    }\n    //} else if (left && left->isAccessible){\n    //    if ((phys = left->getBlockSafe(lockedChunk, c + CHUNK_WIDTH - 1).caIndex) > -1) {\n    //        left->addPhysicsUpdate(phys, c + CHUNK_WIDTH - 1);\n    //    }\n    //} else{\n    //    return;\n    //}\n\n    //if (pos.x < CHUNK_WIDTH - 1){ //right\n    //    if ((phys = chunk->getBlockSafe(lockedChunk, c + 1).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, c + 1);\n    //    }\n    //} else if (right && right->isAccessible){\n    //    if ((phys = right->getBlockSafe(lockedChunk, c - CHUNK_WIDTH + 1).caIndex) > -1) {\n    //        right->addPhysicsUpdate(phys, c - CHUNK_WIDTH + 1);\n    //    }\n    //} else{\n    //    return;\n    //}\n\n    //if (pos.z > 0){ //back\n    //    if ((phys = chunk->getBlockSafe(lockedChunk, c - CHUNK_WIDTH).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, c - CHUNK_WIDTH);\n    //    }\n    //} else if (back && back->isAccessible){\n    //    if ((phys = back->getBlockSafe(lockedChunk, c + CHUNK_LAYER - CHUNK_WIDTH).caIndex) > -1) {\n    //        back->addPhysicsUpdate(phys, c + CHUNK_LAYER - CHUNK_WIDTH);\n    //    }\n    //} else{\n    //    return;\n    //}\n\n    //if (pos.z < CHUNK_WIDTH - 1){ //front\n    //    if ((phys = chunk->getBlockSafe(lockedChunk, c + CHUNK_WIDTH).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, c + CHUNK_WIDTH);\n    //    }\n    //} else if (front && front->isAccessible){\n    //    if ((phys = front->getBlockSafe(lockedChunk, c - CHUNK_LAYER + CHUNK_WIDTH).caIndex) > -1) {\n    //        front->addPhysicsUpdate(phys, c - CHUNK_LAYER + CHUNK_WIDTH);\n    //    }\n    //} else{\n    //    return;\n    //}\n\n    //if (pos.y > 0){ //bottom\n    //    if ((phys = chunk->getBlockSafe(lockedChunk, c - CHUNK_LAYER).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, c - CHUNK_LAYER);\n    //    }\n    //} else if (bottom && bottom->isAccessible){\n    //    if ((phys = bottom->getBlockSafe(lockedChunk, CHUNK_SIZE - CHUNK_LAYER + c).caIndex) > -1) {\n    //        bottom->addPhysicsUpdate(phys, CHUNK_SIZE - CHUNK_LAYER + c);\n    //    }\n    //} else{\n    //    return;\n    //}\n\n    //if (pos.y < CHUNK_WIDTH - 1){ //top\n    //    if ((phys = chunk->getBlockSafe(lockedChunk, c + CHUNK_LAYER).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, c + CHUNK_LAYER);\n    //    }\n    //} else if (top && top->isAccessible){\n    //    if ((phys = top->getBlockSafe(lockedChunk, c - CHUNK_SIZE + CHUNK_LAYER).caIndex) > -1) {\n    //        top->addPhysicsUpdate(phys, c - CHUNK_SIZE + CHUNK_LAYER);\n    //    }\n    //}\n}\n\nvoid ChunkUpdater::snowAddBlockToUpdateList(Chunk* chunk VORB_UNUSED, int c VORB_UNUSED)\n{\n    //int phys;\n    //const i32v3 pos = getPosFromBlockIndex(c);\n\n    //if ((phys = chunk->getBlock(c).caIndex) > -1) {\n    //    chunk->addPhysicsUpdate(phys, c);\n    //}\n\n    //if (pos.y > 0){ //bottom\n    //    if ((phys = chunk->getBlock(c - CHUNK_LAYER).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, c - CHUNK_LAYER);\n    //    }\n    //} else if (chunk->bottom && chunk->bottom->isAccessible){\n    //    if ((phys = chunk->bottom->getBlock(CHUNK_SIZE - CHUNK_LAYER + c).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, CHUNK_SIZE - CHUNK_LAYER + c);\n    //    }\n    //} else{\n    //    return;\n    //}\n\n    //if (pos.y < CHUNK_WIDTH - 1){ //top\n    //    if ((phys = chunk->getBlock(c + CHUNK_LAYER).caIndex) > -1) {\n    //        chunk->addPhysicsUpdate(phys, c + CHUNK_LAYER);\n    //    }\n    //} else if (chunk->top && chunk->top->isAccessible){\n    //    if ((phys = chunk->top->getBlock(c - CHUNK_SIZE + CHUNK_LAYER).caIndex) > -1) {\n    //        chunk->top->addPhysicsUpdate(phys, c - CHUNK_SIZE + CHUNK_LAYER);\n    //    }\n    //}\n}\n\n//TODO: Replace this with simple emitterOnBreak\n//This function name is misleading, ignore for now\nvoid ChunkUpdater::breakBlock(Chunk* chunk VORB_UNUSED, int x VORB_UNUSED, int y VORB_UNUSED, int z VORB_UNUSED, int blockType VORB_UNUSED, double force VORB_UNUSED, f32v3 extraForce VORB_UNUSED)\n{\n//    f32v4 color;\n//    int btype = GETBLOCKID(blockType);\n//    GLuint flags = GETFLAGS(blockType);\n//\n//    color.a = 255;\n//\n//    if (Blocks[btype].altColors.size() >= flags && flags){\n//        color.r = Blocks[btype].altColors[flags - 1].r;\n//        color.g = Blocks[btype].altColors[flags - 1].g;\n//        color.b = Blocks[btype].altColors[flags - 1].b;\n//        //    cout << btype << \" \" << flags-1 << \" \";\n//    } else{\n//        color.r = Blocks[btype].color.r;\n//        color.g = Blocks[btype].color.g;\n//        color.b = Blocks[btype].color.b;\n//    }\n//\n//    if (Blocks[btype].meshType != MeshType::NONE && Blocks[btype].explosivePower == 0){\n//        if (!chunk->mesh || chunk->mesh->inFrustum){\n////            particleEngine.addParticles(BPARTICLES, f64v3(chunk->gridPosition.x + x, chunk->gridPosition.y + y, chunk->gridPosition.z + z), 0, 0.1, 0, 1, color, Blocks[btype].base.px, 2.0f, 4, extraForce);\n//        }\n//    }\n}\n\n// TODO(Ben): Make this cleaner\nvoid ChunkUpdater::placeFlora(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, int blockID VORB_UNUSED) {\n    //\n    //// Start it out at -1 so when we add 1 we get 0.\n    //ui16 floraHeight = -1;\n    //ui16 floraYpos = -1;\n    //ui16 tertiaryData; \n    //// Get tertiary data\n    //if (blockIndex > CHUNK_LAYER) {\n    //    // Only need the data if its the same plant as we are\n    //    if (chunk->getBlockID(blockIndex - CHUNK_LAYER) == blockID) {\n    //        tertiaryData = chunk->getTertiaryData(blockIndex - CHUNK_LAYER);\n    //        // Grab height and position\n    //        floraHeight = VoxelBits::getFloraHeight(tertiaryData);\n    //        floraYpos = VoxelBits::getFloraPosition(tertiaryData);\n    //    }\n    //} else {\n\n    //    if (chunk->bottom && chunk->bottom->isAccessible) {\n    //        // Only need the data if its the same plant as we are\n    //        if (chunk->bottom->getBlockID(blockIndex - CHUNK_LAYER + CHUNK_SIZE) == blockIndex) {\n    //            tertiaryData = chunk->bottom->getTertiaryData(blockIndex - CHUNK_LAYER + CHUNK_SIZE);\n    //            // Grab height and position\n    //            floraHeight = VoxelBits::getFloraHeight(tertiaryData);\n    //            floraYpos = VoxelBits::getFloraPosition(tertiaryData);\n    //        }\n    //    } else {\n    //        return;\n    //    }\n    //}\n    //tertiaryData = 0;\n    //floraHeight += 1; // add one since we are bigger now\n    //// Add 1 to the tertiary data\n    //VoxelBits::setFloraHeight(tertiaryData, floraHeight);\n    //VoxelBits::setFloraPosition(tertiaryData, floraYpos + 1);\n    //// Set it\n    //chunk->setTertiaryData(blockIndex, tertiaryData);\n    //// Loop downwards through all flora blocks of the same type and increase their height by 1\n    //while (true) {\n    //    // Move the index down\n    //    if (blockIndex >= CHUNK_LAYER) {\n    //        blockIndex -= CHUNK_LAYER;\n    //    } else {\n    //        if (chunk->bottom && chunk->bottom->isAccessible) {\n    //            chunk = chunk->bottom;\n    //        } else {\n    //            return;\n    //        }\n    //        blockIndex = blockIndex - CHUNK_LAYER + CHUNK_SIZE;\n    //    }\n\n    //    // Loop while this is the same block type\n    //    if (chunk->getBlockID(blockIndex) == blockID) {\n    //        tertiaryData = chunk->getTertiaryData(blockIndex);\n    //        // Set new flora height\n    //        VoxelBits::setFloraHeight(tertiaryData, floraHeight);\n    //        chunk->setTertiaryData(blockIndex, tertiaryData);\n    //    } else {\n    //        return;\n    //    }\n\n    //}\n}\n\nvoid ChunkUpdater::removeFlora(ChunkManager* chunkManager VORB_UNUSED, PhysicsEngine* physicsEngine VORB_UNUSED, Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED, int blockID VORB_UNUSED) {\n    //// Grab tertiary data\n    //ui16 tertiaryData = chunk->getTertiaryData(blockIndex);\n    //// Grab height and position\n    //ui16 floraYpos = VoxelBits::getFloraPosition(tertiaryData);\n    //// Set tertiary data to 0\n    //chunk->setTertiaryData(blockIndex, 0);\n\n    //// Recursively kill above flora blocks\n    //blockIndex += CHUNK_LAYER;\n    //if (blockIndex < CHUNK_SIZE) {\n    //    if (chunk->getBlockID(blockIndex) == blockID) {\n    //        removeBlockSafe(chunkManager, physicsEngine, chunk, lockedChunk, blockIndex, true);\n    //    }\n    //} else if (chunk->top && chunk->top->isAccessible) {\n    //    blockIndex -= CHUNK_SIZE;\n    //    if (chunk->top->getBlockID(blockIndex) == blockID) {\n    //        removeBlockSafe(chunkManager, physicsEngine, chunk->top, lockedChunk, blockIndex, true);\n    //    }\n    //}\n}\n\nfloat ChunkUpdater::getBurnProbability(Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED)\n{\n\n    //float flammability = 0.0f;\n    //// Bottom\n    //int bt = vvox::getBottomBlockData(chunk, lockedChunk, blockIndex);\n    //if (bt == -1) return 0.0f;\n    //flammability += GETBLOCK(bt).flammability;\n    //// Left\n    //bt = vvox::getLeftBlockData(chunk, lockedChunk, blockIndex);\n    //if (bt == -1) return 0.0f;\n    //flammability += GETBLOCK(bt).flammability;\n    //// Right\n    //bt = vvox::getRightBlockData(chunk, lockedChunk, blockIndex);\n    //if (bt == -1) return 0.0f;\n    //flammability += GETBLOCK(bt).flammability;\n    //// Back\n    //bt = vvox::getBackBlockData(chunk, lockedChunk, blockIndex);\n    //if (bt == -1) return 0.0f;\n    //flammability += GETBLOCK(bt).flammability;\n    //// Front\n    //bt = vvox::getFrontBlockData(chunk, lockedChunk, blockIndex);\n    //if (bt == -1) return 0.0f;\n    //flammability += GETBLOCK(bt).flammability;\n    //// Top\n    //bt = vvox::getTopBlockData(chunk, lockedChunk, blockIndex);\n    //if (bt == -1) return 0.0f;\n    //flammability += GETBLOCK(bt).flammability;\n\n    //if (flammability < 0) return 0.0f;\n\n    //return flammability / 6.0f;\n    return 0.0f;\n}\n\nvoid ChunkUpdater::updateFireBlock(ChunkManager* chunkManager VORB_UNUSED, PhysicsEngine* physicsEngine VORB_UNUSED, Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED) {\n    ////left\n    //int blockIndex2, blockIndex3, blockIndex4;\n    //Chunk *owner2, *owner3, *owner4;\n    //int bt;\n\n    //const i32v3 pos = getPosFromBlockIndex(blockIndex);\n\n    //const f32 sideTopMult = 1.5f;\n    //const f32 topMult = 2.0f;\n    //const f32 sideBotMult = 0.5f;\n    //const f32 botMult = 0.8f;\n\n    //Chunk* lockedChunk = nullptr;\n\n    //burnAdjacentBlocks(chunkManager, physicsEngine, chunk, lockedChunk, blockIndex);\n\n    ////********************************************************left\n    //bt = vvox::getLeftBlockData(chunk, lockedChunk, blockIndex, pos.x, blockIndex2, owner2);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex2, lockedChunk, bt, owner2);\n\n    ////left front\n    //bt = vvox::getFrontBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3);\n\n    ////left back\n    //bt = vvox::getBackBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3);\n\n    ////left top\n    //bt = vvox::getTopBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideTopMult);\n\n\n    ////left top front\n    //bt = vvox::getFrontBlockData(owner3, lockedChunk, blockIndex3, blockIndex4, owner4);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex4, lockedChunk, bt, owner4, sideTopMult);\n\n    ////left top back\n    //bt = vvox::getBackBlockData(owner3, lockedChunk, blockIndex3, blockIndex4, owner4);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex4, lockedChunk, bt, owner4, sideTopMult);\n\n    ////left bottom\n    //bt = vvox::getBottomBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideBotMult);\n\n    ////left bottom front\n    //bt = vvox::getFrontBlockData(owner3, lockedChunk, blockIndex3, blockIndex4, owner4);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex4, lockedChunk, bt, owner4, sideBotMult);\n\n    ////left bottom back\n    //bt = vvox::getBackBlockData(owner3, lockedChunk, blockIndex3, blockIndex4, owner4);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex4, lockedChunk, bt, owner4, sideBotMult);\n\n    ////********************************************************right\n    //bt = vvox::getRightBlockData(chunk, lockedChunk, blockIndex, pos.x, blockIndex2, owner2);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex2, lockedChunk, bt, owner2);\n\n    ////left front\n    //bt = vvox::getFrontBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3);\n\n    ////left back\n    //bt = vvox::getBackBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3);\n\n    ////left top\n    //bt = vvox::getTopBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideTopMult);\n\n\n    ////left top front\n    //bt = vvox::getFrontBlockData(owner3, lockedChunk, blockIndex3, blockIndex4, owner4);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex4, lockedChunk, bt, owner4, sideTopMult);\n\n    ////left top back\n    //bt = vvox::getBackBlockData(owner3, lockedChunk, blockIndex3, blockIndex4, owner4);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex4, lockedChunk, bt, owner4, sideTopMult);\n\n    ////left bottom\n    //bt = vvox::getBottomBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideBotMult);\n\n    ////left bottom front\n    //bt = vvox::getFrontBlockData(owner3, lockedChunk, blockIndex3, blockIndex4, owner4);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex4, lockedChunk, bt, owner4, sideBotMult);\n\n    ////left bottom back\n    //bt = vvox::getBackBlockData(owner3, lockedChunk, blockIndex3, blockIndex4, owner4);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex4, lockedChunk, bt, owner4, sideBotMult);\n\n    ////******************************************************front\n    //bt = vvox::getFrontBlockData(chunk, lockedChunk, blockIndex, pos.z, blockIndex2, owner2);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex2, lockedChunk, bt, owner2);\n\n    ////front top\n    //bt = vvox::getTopBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideTopMult);\n\n    ////front bottom\n    //bt = vvox::getBottomBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideBotMult);\n\n    ////********************************************************back\n    //bt = vvox::getBackBlockData(chunk, lockedChunk, blockIndex, pos.z, blockIndex2, owner2);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex2, lockedChunk, bt, owner2);\n\n    ////back top\n    //bt = vvox::getTopBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideTopMult);\n\n    ////back bottom\n    //bt = vvox::getBottomBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideBotMult);\n\n    ////********************************************************top\n    //bt = vvox::getTopBlockData(chunk, lockedChunk, blockIndex, pos.y, blockIndex2, owner2);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex2, lockedChunk, bt, owner2, topMult);\n\n    ////top front\n    //bt = vvox::getFrontBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideTopMult);\n\n    ////top back\n    //bt = vvox::getBackBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideTopMult);\n\n\n    ////********************************************************bottom\n    //bt = vvox::getBottomBlockData(chunk, lockedChunk, blockIndex, pos.y, blockIndex2, owner2);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex2, lockedChunk, bt, owner2, botMult);\n\n    ////bottom front\n    //bt = vvox::getFrontBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideBotMult);\n\n    ////bottom back\n    //bt = vvox::getBackBlockData(owner2, lockedChunk, blockIndex2, blockIndex3, owner3);\n    //if (bt == -1) { if (lockedChunk) { lockedChunk->unlock(); }; return; }\n    //checkBurnBlock(blockIndex3, lockedChunk, bt, owner3, sideBotMult);\n\n    //removeBlockSafe(chunkManager, physicsEngine, chunk, lockedChunk, blockIndex, false);\n\n    //if (lockedChunk) lockedChunk->unlock();\n}\n\nvoid ChunkUpdater::burnAdjacentBlocks(ChunkManager* chunkManager VORB_UNUSED, PhysicsEngine* physicsEngine VORB_UNUSED, Chunk* chunk VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockIndex VORB_UNUSED){\n\n    //int blockIndex2;\n    //Chunk *owner2;\n    //Block *b;\n\n    //const i32v3 pos = getPosFromBlockIndex(blockIndex);\n\n    //int bt = vvox::getBottomBlockData(chunk, lockedChunk, blockIndex, pos.y, blockIndex2, owner2);\n    //b = &(GETBLOCK(bt));\n    //if (b->flammability){\n    //    if (b->burnTransformID == NONE){\n    //        removeBlockSafe(chunkManager, physicsEngine, owner2, lockedChunk, blockIndex2, true);\n    //    } else{\n    //        if (Blocks[b->burnTransformID].emitter){\n    //            particleEngine.addEmitter(Blocks[b->burnTransformID].emitter, f64v3(owner2->voxelPosition.x + blockIndex2%CHUNK_WIDTH, owner2->voxelPosition.y + blockIndex2 / CHUNK_LAYER, owner2->voxelPosition.z + (blockIndex2%CHUNK_LAYER) / CHUNK_WIDTH), b->burnTransformID);\n    //        }\n    //        owner2->setBlockDataSafe(lockedChunk, blockIndex2, b->burnTransformID);\n    //    }\n    //    owner2->changeState(ChunkStates::MESH);\n    //}\n    ////left\n    //bt = vvox::getLeftBlockData(chunk, lockedChunk, blockIndex, pos.x, blockIndex2, owner2);\n    //b = &(GETBLOCK(bt));\n    //if (b->flammability){\n    //    if (b->burnTransformID == NONE){\n    //        removeBlockSafe(chunkManager, physicsEngine, owner2, lockedChunk, blockIndex2, true);\n    //    } else{\n    //        if (Blocks[b->burnTransformID].emitter){\n    //            particleEngine.addEmitter(Blocks[b->burnTransformID].emitter, f64v3(owner2->voxelPosition.x + blockIndex2%CHUNK_WIDTH, owner2->voxelPosition.y + blockIndex2 / CHUNK_LAYER, owner2->voxelPosition.z + (blockIndex2%CHUNK_LAYER) / CHUNK_WIDTH), b->burnTransformID);\n    //        }\n    //        owner2->setBlockDataSafe(lockedChunk, blockIndex2, b->burnTransformID);\n    //    }\n    //    owner2->changeState(ChunkStates::MESH);\n    //}\n    ////right\n    //bt = vvox::getRightBlockData(chunk, lockedChunk, blockIndex, pos.x, blockIndex2, owner2);\n    //b = &(GETBLOCK(bt));\n    //if (b->flammability){\n    //    if (b->burnTransformID == NONE){\n    //        removeBlockSafe(chunkManager, physicsEngine, owner2, lockedChunk, blockIndex2, true);\n    //    } else{\n    //        if (Blocks[b->burnTransformID].emitter){\n    //            particleEngine.addEmitter(Blocks[b->burnTransformID].emitter, f64v3(owner2->voxelPosition.x + blockIndex2%CHUNK_WIDTH, owner2->voxelPosition.y + blockIndex2 / CHUNK_LAYER, owner2->voxelPosition.z + (blockIndex2%CHUNK_LAYER) / CHUNK_WIDTH), b->burnTransformID);\n    //        }\n    //        owner2->setBlockDataSafe(lockedChunk, blockIndex2, b->burnTransformID);\n    //    }\n    //    owner2->changeState(ChunkStates::MESH);\n    //}\n    ////back\n    //bt = vvox::getBackBlockData(chunk, lockedChunk, blockIndex, pos.z, blockIndex2, owner2);\n    //b = &(GETBLOCK(bt));\n    //if (b->flammability){\n    //    if (b->burnTransformID == NONE){\n    //        removeBlockSafe(chunkManager, physicsEngine, owner2, lockedChunk, blockIndex2, true);\n    //    } else{\n    //        if (Blocks[b->burnTransformID].emitter){\n    //            particleEngine.addEmitter(Blocks[b->burnTransformID].emitter, f64v3(owner2->voxelPosition.x + blockIndex2%CHUNK_WIDTH, owner2->voxelPosition.y + blockIndex2 / CHUNK_LAYER, owner2->voxelPosition.z + (blockIndex2%CHUNK_LAYER) / CHUNK_WIDTH), b->burnTransformID);\n    //        }\n    //        owner2->setBlockDataSafe(lockedChunk, blockIndex2, b->burnTransformID);\n    //    }\n    //    owner2->changeState(ChunkStates::MESH);\n    //}\n    ////front\n    //bt = vvox::getFrontBlockData(chunk, lockedChunk, blockIndex, pos.z, blockIndex2, owner2);\n    //b = &(GETBLOCK(bt));\n    //if (b->flammability){\n    //    if (b->burnTransformID == NONE){\n    //        removeBlockSafe(chunkManager, physicsEngine, owner2, lockedChunk, blockIndex2, true);\n    //    } else{\n    //        if (Blocks[b->burnTransformID].emitter){\n    //            particleEngine.addEmitter(Blocks[b->burnTransformID].emitter, f64v3(owner2->voxelPosition.x + blockIndex2%CHUNK_WIDTH, owner2->voxelPosition.y + blockIndex2 / CHUNK_LAYER, owner2->voxelPosition.z + (blockIndex2%CHUNK_LAYER) / CHUNK_WIDTH), b->burnTransformID);\n    //        }\n    //        owner2->setBlockDataSafe(lockedChunk, blockIndex2, b->burnTransformID);\n    //    }\n    //    owner2->changeState(ChunkStates::MESH);\n    //}\n    ////top\n    //bt = vvox::getTopBlockData(chunk, lockedChunk, blockIndex, pos.y, blockIndex2, owner2);\n    //b = &(GETBLOCK(bt));\n    //if (b->flammability){\n    //    if (b->burnTransformID == NONE){\n    //        removeBlockSafe(chunkManager, physicsEngine, owner2, lockedChunk, blockIndex2, true);\n    //    } else{\n    //        if (Blocks[b->burnTransformID].emitter){\n    //            particleEngine.addEmitter(Blocks[b->burnTransformID].emitter, f64v3(owner2->voxelPosition.x + blockIndex2%CHUNK_WIDTH, owner2->voxelPosition.y + blockIndex2 / CHUNK_LAYER, owner2->voxelPosition.z + (blockIndex2%CHUNK_LAYER) / CHUNK_WIDTH), b->burnTransformID);\n    //        }\n    //        owner2->setBlockDataSafe(lockedChunk, blockIndex2, b->burnTransformID);\n    //    }\n    //    owner2->changeState(ChunkStates::MESH);\n    //}\n}\n\nvoid ChunkUpdater::checkBurnBlock(int blockIndex VORB_UNUSED, Chunk*& lockedChunk VORB_UNUSED, int blockType VORB_UNUSED, Chunk *owner VORB_UNUSED, float burnMult VORB_UNUSED)\n{\n   /* float burnProb;\n    if ((blockType == NONE || GETBLOCK(blockType).waterBreak)){\n        burnProb = getBurnProbability(owner, lockedChunk, blockIndex) * burnMult;\n        if (burnProb > 0){\n            float r = rand() / (float)RAND_MAX;\n            if (r <= burnProb){\n               placeBlockSafe(owner, lockedChunk, blockIndex, FIRE);\n            }\n        }\n    }*/\n}"
  },
  {
    "path": "SoA/ChunkUpdater.h",
    "content": "#pragma once\n#include \"Constants.h\"\n\n// TODO(Ben): Temporary\n#include \"BlockData.h\"\n#include \"Chunk.h\"\n\n#include \"VoxelUpdateBufferer.h\"\n\nclass PhysicsEngine;\nclass ChunkManager;\nclass BlockPack;\nenum class ChunkStates;\n\nclass ChunkUpdater {\npublic:\n    static void randomBlockUpdates(PhysicsEngine* physicsEngine, Chunk* chunk);\n    static void placeBlock(VoxelUpdateBufferer& bufferer, Chunk* chunk, Chunk*& lockedChunk VORB_UNUSED, BlockIndex blockIndex, BlockID blockData) {\n        updateBlockAndNeighbors(bufferer, chunk, blockIndex, blockData);\n        // TODO: Is this call needed? If so, reimplement and remove VORB_UNUSED tags.\n        //addBlockToUpdateList(chunk, lockedChunk, blockIndex);\n    }\n    static void placeBlockSafe(Chunk* chunk, Chunk*& lockedChunk, BlockIndex blockIndex, BlockID blockData);\n    static void placeBlockNoUpdate(Chunk* chunk, BlockIndex blockIndex, BlockID blockType);\n    static void placeBlockFromLiquidPhysics(Chunk* chunk, Chunk*& lockedChunk, int blockIndex, int blockType);\n    static void placeBlockFromLiquidPhysicsSafe(Chunk* chunk, Chunk*& lockedChunk, int blockIndex, int blockType);\n  \n    static void removeBlock(ChunkManager* chunkManager, PhysicsEngine* physicsEngine, Chunk* chunk, Chunk*& lockedChunk, int blockIndex, bool isBreak, double force = 0.0, f32v3 explodeDir = f32v3(0.0f));\n    static void removeBlockSafe(ChunkManager* chunkManager, PhysicsEngine* physicsEngine, Chunk* chunk, Chunk*& lockedChunk, int blockIndex, bool isBreak, double force = 0.0, f32v3 explodeDir = f32v3(0.0f));\n    static void removeBlockFromLiquidPhysics(Chunk* chunk, Chunk*& lockedChunk, int blockIndex);\n    static void removeBlockFromLiquidPhysicsSafe(Chunk* chunk, Chunk*& lockedChunk, int blockIndex);\n\n    static void updateNeighborStates(Chunk* chunk, const i32v3& pos, ChunkStates state);\n    static void updateNeighborStates(Chunk* chunk, int blockID, ChunkStates state);\n\n    // Assumes chunk is already locked.\n    static void updateBlockAndNeighbors(VoxelUpdateBufferer& bufferer, Chunk* chunk, BlockIndex index);\n    static void updateBlockAndNeighbors(VoxelUpdateBufferer& bufferer, Chunk* chunk, BlockIndex index, BlockID id);\n    static void snowAddBlockToUpdateList(Chunk* chunk, int c);\n\n    static BlockPack* blockPack;\nprivate:\n    //TODO: Replace with emitterOnBreak\n    static void breakBlock(Chunk* chunk, int x, int y, int z, int blockType, double force = 0.0f, f32v3 extraForce = f32v3(0.0f));\n\n    static void placeFlora(Chunk* chunk, int blockIndex, int blockID);\n    static void removeFlora(ChunkManager* chunkManager, PhysicsEngine* physicsEngine, Chunk* chunk, Chunk*& lockedChunk, int blockIndex, int blockID);\n\n    //Fire\n    static void updateFireBlock(ChunkManager* chunkManager, PhysicsEngine* physicsEngine, Chunk* chunk, int blockIndex);\n    static float getBurnProbability(Chunk* chunk, Chunk*& lockedChunk, int blockIndex);\n    static void burnAdjacentBlocks(ChunkManager* chunkManager, PhysicsEngine* physicsEngine, Chunk* chunk, Chunk*& lockedChunk, int blockIndex);\n    static inline void checkBurnBlock(int blockIndex, Chunk*& lockedChunk, int blockType, Chunk *owner, float burnMult = 1.0);\n};"
  },
  {
    "path": "SoA/ClientState.h",
    "content": "//\n// ClientState.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 11 Aug 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// State for the client only.\n//\n\n#pragma once\n\n#ifndef ClientState_h__\n#define ClientState_h__\n\n#include \"BlockTextureLoader.h\"\n#include \"BlockTexturePack.h\"\n#include \"Camera.h\"\n#include \"MainMenuSystemViewer.h\"\n#include \"ModPathResolver.h\"\n#include \"VoxelEditor.h\"\n\nclass DebugRenderer;\n\nclass ChunkMeshManager;\n\nstruct ClientState {\n    ChunkMeshManager* chunkMeshManager = nullptr;\n    // TODO(Ben): Commonstate\n    DebugRenderer* debugRenderer = nullptr;\n    MainMenuSystemViewer* systemViewer = nullptr;\n\n    BlockTextureLoader blockTextureLoader;\n    BlockTexturePack* blockTextures = nullptr;\n    ModPathResolver texturePathResolver;\n    VoxelEditor voxelEditor; // TODO(Ben): Should maybe be server side?\n\n    vecs::EntityID startingPlanet = 0;\n    vecs::EntityID playerEntity = 0;\n\n    // TODO(Ben): This is temporary!\n    CinematicCamera spaceCamera; ///< The camera that looks at the planet from space\n\n    bool isNewGame = true;\n    f64v3 startSpacePos = f64v3(0.0f); ///< Starting position of player entity\n};\n\n#endif // ClientState_h__\n"
  },
  {
    "path": "SoA/CloseTerrainPatch.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TerrainPatch.h\"\n\n#include <Vorb/utils.h>\n\n#include \"BlockData.h\"\n#include \"Chunk.h\"\n#include \"FloraGenerator.h\"\n#include \"GameManager.h\"\n//#include \"Options.h\"\n#include \"Planet.h\"\n#include \"WorldStructs.h\"\n\ninline double BilinearInterpolation(int &a, int &b, int &c, int &d, int &step, float &x, float &z)\n{\n    double px, pz;\n    px = ((double)(x)) / step;\n    pz = ((double)(z)) / step;\n\n    return  (a)*(1 - px)*(1 - pz) +\n        (b)*px*(1 - pz) +\n        (c)*(1 - px)*pz +\n        (d)*px*pz;\n}\n\nCloseTerrainPatch::CloseTerrainPatch(int lodWidth){\n    for (int i = 0; i < 4; i++){\n        lods[i] = NULL;\n    }\n    width = lodWidth;\n    vboID = 0;\n    vaoID = 0;\n    vboIndexID = 0;\n    updateVecIndex = -1;\n    vecIndex = -1;\n    treeVboID = 0;\n    treeIndexSize = 0;\n    lodMap = NULL;\n}\n\nCloseTerrainPatch::~CloseTerrainPatch(){\n    ClearLODMap();\n    ClearBuffers();\n    DeleteChildren();\n}\n\nvoid CloseTerrainPatch::ClearLODMap()\n{\n    if (lodMap != NULL){\n        delete[] lodMap;\n        lodMap = NULL;\n    }\n}\n\nvoid CloseTerrainPatch::ClearBuffers()\n{\n    indexSize = 0;\n    if (vboID != 0){\n        glDeleteVertexArrays(1, &vaoID);\n        glDeleteBuffers(1, &vboID);\n        vaoID = 0;\n        vboID = 0;\n    }\n    if (vboIndexID != 0){\n        glDeleteBuffers(1, &vboIndexID);\n        vboIndexID = 0;\n    }\n    ClearTreeBuffers();\n}\n\nvoid CloseTerrainPatch::ClearTreeBuffers()\n{\n    treeIndexSize = 0;\n    if (treeVboID != 0){\n        glDeleteBuffers(1, &treeVboID);\n        treeVboID = 0;\n    }\n}\n\nvoid CloseTerrainPatch::DeleteChildren()\n{\n    if (lods[0]){\n        for (unsigned int i = 0; i < 4; i++){\n            lods[i]->ClearBuffers();\n            lods[i]->DeleteChildren();\n            delete lods[i]; //calls delete children\n            lods[i] = NULL;\n        }\n    }\n}\n\n//itinializes the LOD and computes distance\nvoid CloseTerrainPatch::Initialize(int x, int y, int z, int wx, int wy, int wz, CloseTerrainPatch *Parent, int ChildNum, int initialDetailLevel)\n{\n    childNum = ChildNum;\n    waitForMesh = 0;\n    vboID = 0;\n    vaoID = 0;\n    treeVboID = 0;\n    drawTrees = 0;\n    lodMap = NULL;\n    vboIndexID = 0;\n    for (unsigned int i = 0; i < 4; i++){\n        lods[i] = NULL;\n    }\n    indexSize = 0;\n    treeIndexSize = 0;\n    parent = Parent;\n    updateCode = 1;\n    vecIndex = -1;\n    updateVecIndex = -1;\n    hasSkirt = 1;\n    hasBoundingBox = 0;\n    cullRadius = 0;\n    hasProperDist = 0;\n\n    X = x;\n    Y = y;\n    Z = z;\n\n    double vx = X + width / 2;\n    double vy = Y + width / 2;\n    double vz = Z + width / 2;\n\n    //double tmph = currTerrainGenerator->GenerateSingleHeight(vx, vy, vz);\n\n    double magnitude = sqrt(vx*vx + vy*vy + vz*vz);\n    vx /= magnitude;\n    vy /= magnitude;\n    vz /= magnitude;\n\n    closestPoint.x = X + width/2;\n    closestPoint.y = Y + width / 2;\n    closestPoint.z = Z + width / 2;\n\n    double dx = (double)(X - wx);\n    double dy = (double)(Y - wy);\n    double dz = (double)(Z - wz);\n    //approximate distance, not true distance until mesh has been made initially\n    distance = sqrt(dx*dx + dy*dy + dz*dz) - width*0.5*1.4142;\n    if (distance < 0) distance = 0;\n\n    hasMesh = 0;\n    if (initialDetailLevel != -1){\n        detailLevel = initialDetailLevel;\n        step = lodDetailLevels[detailLevel + graphicsOptions.lodDetail];\n        waitForMesh = 1;\n    }\n    else{\n        CalculateDetailLevel(distance, 0);\n    }\n\n    if (detailLevel == 0) hasSkirt = 0;\n    if ((width / step) > maxVertexWidth){\n        CreateChildren(wx, wy, wz);\n    }\n}\n\nvoid CloseTerrainPatch::Draw(glm::dvec3 &PlayerPos, glm::dvec3 &rotPlayerPos, glm::mat4 &VP, GLuint mvpID, GLuint worldOffsetID, bool onPlanet)\n{\n//    if (indexSize){\n//        if (distance < closestTerrainPatchDistance) closestTerrainPatchDistance = distance;\n//        if (SphereInFrustum((float)(boundingBox.x / 2 - rotPlayerPos.x), (float)(boundingBox.y / 2 - rotPlayerPos.y), (float)(boundingBox.z / 2 - rotPlayerPos.z), (float)cullRadius, worldFrustum)){\n//\n//            glm::mat4 MVP;\n//\n//            GlobalModelMatrix[3][0] = ((float)((double)X - PlayerPos.x));\n//            GlobalModelMatrix[3][1] = ((float)((double)Y - PlayerPos.y));\n//            GlobalModelMatrix[3][2] = ((float)((double)Z - PlayerPos.z));\n//            MVP = VP  * GlobalModelMatrix;\n//\n//            glUniformMatrix4fv(mvpID, 1, GL_FALSE, &MVP[0][0]); //some kind of crash here :/\n//\n////            glUniform3f(worldOffsetID, drawX, drawY, drawZ);\n//\n//\n//            //    glBindBuffer(GL_ARRAY_BUFFER, vboID);\n//            //    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexID);\n//\n//\n//            glBindVertexArray(vaoID);\n//            glDrawElements(GL_TRIANGLES, indexSize, GL_UNSIGNED_SHORT, 0);\n//            glBindVertexArray(0);\n//        }\n//    }\n//    else if (lods[0]){\n//        lods[0]->Draw(PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n//        lods[1]->Draw(PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n//        lods[2]->Draw(PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n//        lods[3]->Draw(PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n//    }\n}\n\nvoid CloseTerrainPatch::DrawTrees(glm::dvec3 &PlayerPos, glm::mat4 &VP)\n{\n    //if (treeIndexSize){\n    //    if (SphereInFrustum((float)(worldX + boundingBox.x / 2 - PlayerPos.x), (float)(worldY + boundingBox.y / 2 - PlayerPos.y), (float)(worldZ + boundingBox.z / 2 - PlayerPos.z), (float)cullRadius)\n    //        && CheckHorizon(PlayerPos)){\n\n    //        GlobalModelMatrix[3][0] = ((float)((double)drawX - PlayerPos.x));\n    //        GlobalModelMatrix[3][1] = ((float)((double)drawY - PlayerPos.y));\n    //        GlobalModelMatrix[3][2] = ((float)((double)drawZ - PlayerPos.z));\n\n    //        glm::mat4 MVP = VP * GlobalModelMatrix;\n\n    //        glUniformMatrix4fv(treeShader.mvpID, 1, GL_FALSE, &MVP[0][0]);\n    //        glUniformMatrix4fv(treeShader.mID, 1, GL_FALSE, &GlobalModelMatrix[0][0]);\n    //        //glUniformMatrix4fv(treeShader.mvpID, 1, GL_FALSE, &MVP[0][0]);\n    //        //glUniformMatrix4fv(treeShader.gVPID, 1, GL_FALSE, &VP[0][0]);\n    //        //glUniform3f(treeShader.upID, worldNormal.x, worldNormal.y, worldNormal.z);\n\n    //        totVertices += treeIndexSize;\n    //        totDrawCalls++;\n\n    //        glBindBuffer(GL_ARRAY_BUFFER, treeVboID);\n\n    //        //position\n    //        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TreeVertex), 0);\n    //        //particle center\n    //        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(TreeVertex), ((char *)NULL + (8)));\n    //        //leaf color and size\n    //        glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(TreeVertex), ((char *)NULL + (20)));\n    //        //trunk color and ltex\n    //        glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(TreeVertex), ((char *)NULL + (24)));\n\n    //        glDrawElements(GL_TRIANGLES, treeIndexSize, GL_UNSIGNED_INT, NULL);\n    //    }\n    //}\n    //else if (lods[0]){\n    //    lods[0]->DrawTrees(PlayerPos, VP);\n    //    lods[1]->DrawTrees(PlayerPos, VP);\n    //    lods[2]->DrawTrees(PlayerPos, VP);\n    //    lods[3]->DrawTrees(PlayerPos, VP);\n    //}\n}\n\nconst bool colorDebug = 0;\nbool CloseTerrainPatch::CreateMesh()\n{\n    \n\n    return 1;\n}\n\nvoid CloseTerrainPatch::CreateChildren(int wx, int wy, int wz, int initialDetail)\n{\n    int hw = width / 2;\n\n    lods[0] = new CloseTerrainPatch(hw);\n    lods[1] = new CloseTerrainPatch(hw);\n    lods[2] = new CloseTerrainPatch(hw);\n    lods[3] = new CloseTerrainPatch(hw);\n\n    lods[0]->Initialize(X, 0, Z, wx, wy, wz, this, 0, initialDetail);\n    lods[1]->Initialize(X + hw, 0, Z, wx, wy, wz, this, 1, initialDetail);\n    lods[2]->Initialize(X, 0, Z + hw, wx, wy, wz, this, 2, initialDetail);\n    lods[3]->Initialize(X + hw, 0, Z + hw, wx, wy, wz, this, 3, initialDetail);\n\n    /*switch (face){\n    case P_TOP:\n        lods[0]->Initialize(X, scaledRadius, Z, wx, wy, wz, radius, face, this, 0, initialDetail);\n        lods[1]->Initialize(X + hw, scaledRadius, Z, wx, wy, wz, radius, face, this, 1, initialDetail);\n        lods[2]->Initialize(X, scaledRadius, Z + hw, wx, wy, wz, radius, face, this, 2, initialDetail);\n        lods[3]->Initialize(X + hw, scaledRadius, Z + hw, wx, wy, wz, radius, face, this, 3, initialDetail);\n        break;\n    case P_LEFT:\n        lods[0]->Initialize(-scaledRadius, Y, Z, wx, wy, wz, radius, face, this, 0, initialDetail);\n        lods[1]->Initialize(-scaledRadius, Y, Z + hw, wx, wy, wz, radius, face, this, 1, initialDetail);\n        lods[2]->Initialize(-scaledRadius, Y + hw, Z, wx, wy, wz, radius, face, this, 2, initialDetail);\n        lods[3]->Initialize(-scaledRadius, Y + hw, Z + hw, wx, wy, wz, radius, face, this, 3, initialDetail);\n        break;\n    case P_RIGHT:\n        lods[0]->Initialize(scaledRadius, Y, Z, wx, wy, wz, radius, face, this, 0, initialDetail);\n        lods[1]->Initialize(scaledRadius, Y, Z + hw, wx, wy, wz, radius, face, this, 1, initialDetail);\n        lods[2]->Initialize(scaledRadius, Y + hw, Z, wx, wy, wz, radius, face, this, 2, initialDetail);\n        lods[3]->Initialize(scaledRadius, Y + hw, Z + hw, wx, wy, wz, radius, face, this, 3, initialDetail);\n        break;\n    case P_FRONT:\n        lods[0]->Initialize(X, Y, scaledRadius, wx, wy, wz, radius, face, this, 0, initialDetail);\n        lods[1]->Initialize(X + hw, Y, scaledRadius, wx, wy, wz, radius, face, this, 1, initialDetail);\n        lods[2]->Initialize(X, Y + hw, scaledRadius, wx, wy, wz, radius, face, this, 2, initialDetail);\n        lods[3]->Initialize(X + hw, Y + hw, scaledRadius, wx, wy, wz, radius, face, this, 3, initialDetail);\n        break;\n    case P_BACK:\n        lods[0]->Initialize(X, Y, -scaledRadius, wx, wy, wz, radius, face, this, 0, initialDetail);\n        lods[1]->Initialize(X + hw, Y, -scaledRadius, wx, wy, wz, radius, face, this, 1, initialDetail);\n        lods[2]->Initialize(X, Y + hw, -scaledRadius, wx, wy, wz, radius, face, this, 2, initialDetail);\n        lods[3]->Initialize(X + hw, Y + hw, -scaledRadius, wx, wy, wz, radius, face, this, 3, initialDetail);\n        break;\n    case P_BOTTOM:\n        lods[0]->Initialize(X, -scaledRadius, Z, wx, wy, wz, radius, face, this, 0, initialDetail);\n        lods[1]->Initialize(X + hw, -scaledRadius, Z, wx, wy, wz, radius, face, this, 1, initialDetail);\n        lods[2]->Initialize(X, -scaledRadius, Z + hw, wx, wy, wz, radius, face, this, 2, initialDetail);\n        lods[3]->Initialize(X + hw, -scaledRadius, Z + hw, wx, wy, wz, radius, face, this, 3, initialDetail);\n        break;\n    }*/\n}\n\n//returns the update code 0 = no update, 1 = update, 2 = remove children and update\nint CloseTerrainPatch::update(int wx, int wy, int wz)\n{\n    int rv = 0;\n    if (lods[0]){\n        for (unsigned int i = 0; i < 4; i++){\n            if (lods[i]->update(wx, wy, wz)) rv = 1; //if a child needs to change its mesh, we will return 1\n        }\n\n        SortChildren(); //sort children for better mesh updates\n    }\n\n    double dx, dy, dz;\n\n    int oldDetailLevel = detailLevel;\n    int oldStep = step;\n\n    if (hasBoundingBox){ //bounding box distance\n        closestPoint.x = (wx <= X) ? X : ((wx > X + boundingBox.x) ? (X + boundingBox.x) : wx);\n        closestPoint.y = (wy <= Y) ? Y : ((wy > Y + boundingBox.y) ? (Y + boundingBox.y) : wy);\n        closestPoint.z = (wz <= Z) ? Z : ((wz > Z + boundingBox.z) ? (Z + boundingBox.z) : wz);\n\n        dx = (double)(closestPoint.x) - wx;\n        dy = (double)(closestPoint.y) - wy;\n        dz = (double)(closestPoint.z) - wz;\n        distance = sqrt(dx*dx + dy*dy + dz*dz);\n\n        if (hasProperDist){\n            CalculateDetailLevel(distance, 100);\n        }\n        else{\n            CalculateDetailLevel(distance, 0);\n            hasProperDist = 1;\n        }\n    }\n    else{ //approximate distance\n\n        closestPoint.x = X;\n        closestPoint.y = Y;\n        closestPoint.z = Z;\n\n        dx = (double)(X)-wx;\n        dy = (double)(Y)-wy;\n        dz = (double)(Z)-wz;\n        distance = sqrt(dx*dx + dy*dy + dz*dz) - width*0.5*1.4142;\n        if (distance < 0) distance = 0;\n        if (waitForMesh == 0) CalculateDetailLevel(distance, 0); //shorten the distance by the diagonal radius of an LOD\n    }\n\n    if (detailLevel == 0){ //if detail is lowest, we dont need to display a skirt\n        hasSkirt = 0;\n    }\n    else{\n        hasSkirt = 1;\n    }\n\n    //if the detail changed, then we need to reload the mesh.\n    if (detailLevel != oldDetailLevel || step != oldStep){\n\n        //        cout << detailLevel << \" \" << oldDetailLevel << \" \" << (width / step) << \" \" << width << \" \" << step << endl;\n        //if there will be too many vertices for this size of LOD, split it into 4 children\n        if ((width / step) > maxVertexWidth){\n            //if we already have children, we simply return 1 to indicate a needed update.\n            if (lods[0]){\n                updateCode = 1;\n                return 1; //update Children\n            }\n\n            CreateChildren(wx, wy, wz, oldDetailLevel);\n            updateCode = 1;\n            return 1;\n        }\n        else if (lods[0]){  //if we have children but no longer need them, flag for deletion\n            updateCode = 2;\n            return 2; //remove children\n        }\n        updateCode = 1;\n        return 1;//push onto update list\n    }\n\n    if (rv){\n        updateCode = 1;\n    }\n    return rv;\n}\n\nvoid CloseTerrainPatch::CalculateDetailLevel(double dist, int threshold)\n{\n    for (int i = 0; i < DetailLevels; i++){\n        //check if the distance is inside the range for the different detail levels\n        if (dist < lodDistanceLevels[i] - threshold && (i == 0 || dist >= lodDistanceLevels[i - 1] + threshold)){\n            //set the step for meshing and store the new detail level\n            step = lodDetailLevels[i + graphicsOptions.lodDetail];\n            detailLevel = i;\n            break;\n        }\n    }\n}\n\nvoid CloseTerrainPatch::SortChildren()\n{\n    CloseTerrainPatch *temp;\n    int j;\n    for (unsigned int i = 1; i < 4; i++)\n    {\n        temp = lods[i];\n\n        for (j = i - 1; (j >= 0) && (temp->distance < lods[j]->distance); j--)\n        {\n            lods[j + 1] = lods[j];\n            lods[j + 1]->vecIndex = j + 1;\n        }\n\n        lods[j + 1] = temp;\n        lods[j + 1]->vecIndex = j + 1;\n    }\n}\n"
  },
  {
    "path": "SoA/CloudsComponentRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"CloudsComponentRenderer.h\"\n\n#include \"SpaceSystem.h\"\n#include \"RenderUtils.h\"\n#include \"soaUtils.h\"\n#include \"ShaderLoader.h\"\n\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/MeshGenerators.h>\n#include <Vorb/graphics/RasterizerState.h>\n#include <Vorb/graphics/ShaderManager.h>\n\nCloudsComponentRenderer::~CloudsComponentRenderer() {\n    dispose();\n}\n\nvoid CloudsComponentRenderer::initGL() {\n    if (!m_program.isCreated()) {\n        m_program = ShaderLoader::createProgramFromFile(\"Shaders/CloudsShading/Clouds.vert\",\n                                                        \"Shaders/CloudsShading/Clouds.frag\");\n    }\n    if (!m_icoVbo) buildMesh();\n}\n\nvoid CloudsComponentRenderer::draw(const CloudsComponent& cCmp,\n                                   const f32m4& VP,\n                                   const f32v3& relCamPos,\n                                   const f32v3& lightDir,\n                                   const f32 zCoef,\n                                   const SpaceLightComponent* spComponent VORB_MAYBE_UNUSED,\n                                   const AxisRotationComponent& arComponent,\n                                   const AtmosphereComponent& aCmp) {\n    m_program.use();\n\n    f64q invOrientation = glm::inverse(arComponent.currentOrientation);\n    const f32v3 rotpos(invOrientation * f64v3(relCamPos));\n    const f32v3 rotLightDir = f32v3(invOrientation * f64v3(lightDir));\n    // Convert f64q to f32q\n    f32q orientationF32;\n    orientationF32.x = (f32)arComponent.currentOrientation.x;\n    orientationF32.y = (f32)arComponent.currentOrientation.y;\n    orientationF32.z = (f32)arComponent.currentOrientation.z;\n    orientationF32.w = (f32)arComponent.currentOrientation.w;\n    // Convert to matrix\n    f32m4 rotationMatrix = glm::toMat4(orientationF32);\n\n    // Create WVP matrix\n    f32m4 WVP(1.0);\n    setMatrixScale(WVP, f32v3(cCmp.height + cCmp.planetRadius));\n    setMatrixTranslation(WVP, -relCamPos);\n    WVP = VP * WVP * rotationMatrix;\n    \n    // Set uniforms\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, GL_FALSE, &WVP[0][0]);\n    static f32 time = 0.0;\n    time += 0.001f;\n    glUniform1f(m_program.getUniform(\"unTime\"), time);\n    glUniform3fv(m_program.getUniform(\"unColor\"), 1, &cCmp.color[0]);\n    glUniform3fv(m_program.getUniform(\"unNoiseScale\"), 1, &cCmp.scale[0]);\n    glUniform1f(m_program.getUniform(\"unDensity\"), cCmp.density);\n    glUniform1f(m_program.getUniform(\"unCloudsRadius\"), cCmp.planetRadius + cCmp.height);\n    // For logarithmic Z buffer\n    glUniform1f(m_program.getUniform(\"unZCoef\"), zCoef);\n\n    // Scattering\n    f32 camHeight = glm::length(rotpos);\n    // f32 camHeight2 = camHeight * camHeight;\n    glUniform3fv(m_program.getUniform(\"unLightDirWorld\"), 1, &rotLightDir[0]);\n\n    glUniform3fv(m_program.getUniform(\"unCameraPos\"), 1, &rotpos[0]);\n    glUniform3fv(m_program.getUniform(\"unInvWavelength\"), 1, &aCmp.invWavelength4[0]);\n    glUniform1f(m_program.getUniform(\"unCameraHeight2\"), camHeight * camHeight);\n    glUniform1f(m_program.getUniform(\"unOuterRadius\"), aCmp.radius);\n    glUniform1f(m_program.getUniform(\"unOuterRadius2\"), aCmp.radius * aCmp.radius);\n    glUniform1f(m_program.getUniform(\"unInnerRadius\"), aCmp.planetRadius);\n    glUniform1f(m_program.getUniform(\"unKrESun\"), aCmp.kr * aCmp.esun);\n    glUniform1f(m_program.getUniform(\"unKmESun\"), aCmp.km * aCmp.esun);\n    glUniform1f(m_program.getUniform(\"unKr4PI\"), (f32)(aCmp.kr * M_4_PI));\n    glUniform1f(m_program.getUniform(\"unKm4PI\"), (f32)(aCmp.km * M_4_PI));\n    float scale = 1.0f / (aCmp.radius - aCmp.planetRadius);\n    glUniform1f(m_program.getUniform(\"unScale\"), scale);\n    glUniform1f(m_program.getUniform(\"unScaleDepth\"), aCmp.scaleDepth);\n    glUniform1f(m_program.getUniform(\"unScaleOverScaleDepth\"), scale / aCmp.scaleDepth);\n    glUniform1i(m_program.getUniform(\"unNumSamples\"), 3);\n    glUniform1f(m_program.getUniform(\"unNumSamplesF\"), 3.0f);\n    glUniform1f(m_program.getUniform(\"unG\"), aCmp.g);\n    glUniform1f(m_program.getUniform(\"unG2\"), aCmp.g * aCmp.g);\n\n    // Bind VAO\n    glBindVertexArray(m_vao);\n\n    // Render\n    glDepthMask(GL_FALSE);\n\n    if (camHeight > cCmp.planetRadius + cCmp.height) vg::RasterizerState::CULL_CLOCKWISE.set();\n    else vg::RasterizerState::CULL_COUNTER_CLOCKWISE.set();\n    glDrawElements(GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, 0);\n    glDepthMask(GL_TRUE);\n    vg::RasterizerState::CULL_CLOCKWISE.set();\n\n    glBindVertexArray(0);\n\n    m_program.unuse();\n}\n\nvoid CloudsComponentRenderer::dispose() {\n    if (m_program.isCreated()) m_program.dispose();\n    if (m_icoVbo) {\n        vg::GpuMemory::freeBuffer(m_icoVbo);\n        m_icoVbo = 0;\n    }\n    if (m_icoIbo) {\n        vg::GpuMemory::freeBuffer(m_icoIbo);\n        m_icoIbo = 0;\n    }\n    if (m_vao) {\n        glDeleteVertexArrays(1, &m_vao);\n        m_vao = 0;\n    }\n}\n\nvoid CloudsComponentRenderer::buildMesh() {\n    std::vector<ui32> indices;\n    std::vector<f32v3> positions;\n\n    vmesh::generateIcosphereMesh(3, indices, positions);\n    m_numIndices = indices.size();\n\n    glGenVertexArrays(1, &m_vao);\n    glBindVertexArray(m_vao);\n\n    vg::GpuMemory::createBuffer(m_icoVbo);\n    vg::GpuMemory::createBuffer(m_icoIbo);\n\n    vg::GpuMemory::bindBuffer(m_icoVbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_icoVbo, vg::BufferTarget::ARRAY_BUFFER, positions.size() * sizeof(f32v3),\n        positions.data(), vg::BufferUsageHint::STATIC_DRAW);\n\n    vg::GpuMemory::bindBuffer(m_icoIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_icoIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(ui32),\n        indices.data(), vg::BufferUsageHint::STATIC_DRAW);\n\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);\n    m_program.enableVertexAttribArrays();\n\n    glBindVertexArray(0);\n}"
  },
  {
    "path": "SoA/CloudsComponentRenderer.h",
    "content": "#pragma once\n\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/ecs/ComponentTable.hpp>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/graphics/GLProgram.h>\n\nstruct AtmosphereComponent;\nstruct AxisRotationComponent;\nstruct CloudsComponent;\nstruct SpaceLightComponent;\n\nclass CloudsComponentRenderer\n{\npublic:\n    ~CloudsComponentRenderer();\n\n    void initGL();\n    void draw(const CloudsComponent& cCmp,\n              const f32m4& VP,\n              const f32v3& relCamPos,\n              const f32v3& lightDir,\n              const f32 zCoef,\n              const SpaceLightComponent* spComponent,\n              const AxisRotationComponent& arComponent,\n              const AtmosphereComponent& aCmp);\n    void dispose();\nprivate:\n    void buildMesh();\n\n    vg::GLProgram m_program;\n    VGBuffer m_icoVbo = 0;\n    VGIndexBuffer m_icoIbo = 0;\n    VGVertexArray m_vao = 0;\n    int m_numIndices = 0;\n};\n\n"
  },
  {
    "path": "SoA/Collision.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Collision.h\"\n\n#include <Vorb/utils.h>\n\n#include \"Chunk.h\"\n#include \"BlockPack.h\"\n\nvoid blockCollision(Player* player, Chunk*  chunk, Chunk*  lockedChunk, ui16 blockType, i32 c, f64 bdx, f64 bdy, f64 bdz, f64 dx, f64 dy, f64 dz);\n\n//This method could be easily implemented as a recursive function, but is more efficient if unfolded\n//TODO(Ben) This is laughable. \nvoid aabbChunkCollision(Player* player VORB_UNUSED, f64v3* playerPos VORB_UNUSED, Chunk* * chunks VORB_UNUSED, ui8 size VORB_UNUSED)\n{\n    //int x, y, z, x1, y1, z1 ,x2, y2, z2, x3, y3, z3, x4, y4, z4, c; //midpoints\n    //int blockID;\n    //double x5, y5, z5; //only this one requires double precision\n    //double yPosOffset;\n    //double boxX, boxY, boxZ;\n    //double dx, dy, dz, bdx, bdy, bdz;\n    //NChunk* chunk;\n\n    //f32v3 *playerBox = nullptr; // &(player->boundingBox);\n    //boxX = playerBox->x;\n    //boxY = playerBox->y/2.0; //the box point is dead center of the player\n    //boxZ = playerBox->z;\n    //yPosOffset = boxY; //since we are using a center point, we use yPosOffset to move the midpoint from the feet to the center\n\n    //NChunk*  lockedChunk = nullptr;\n\n    //for (unsigned char i = 0; i < size; i++) { //loops through chunks\n\n    //    if (!(chunks[i]) || chunks[i]->isAccessible == false) continue; //avoid errors\n\n    //    //find the midpoint so that we can subdivide the chunk into 8 sections\n    //    x = chunks[i]->voxelPosition.x + CHUNK_WIDTH / 2;\n    //    y = chunks[i]->voxelPosition.y + CHUNK_WIDTH / 2;\n    //    z = chunks[i]->voxelPosition.z + CHUNK_WIDTH / 2;\n\n    //    //checks to see if the distance between the players midpoint and the box midpoint is greater than the radius\n    //    //all three axis must be colliding for a collision\n    //    if ((boxX + 16) < ABS(playerPos->x - x)) continue; \n    //    if ((boxY + 16) < ABS(playerPos->y + yPosOffset - y)) continue;\n    //    if ((boxZ + 16) < ABS(playerPos->z - z)) continue;\n\n    //    for (unsigned char l0 = 0; l0 < 2; l0++){ //zeroth subdivide\n    //        //loops through each of the smaller boxes, setting x1, y1, z1 to the midpoint\n    //        if (l0 == 0){\n    //            y1 = y + 8;\n    //        }else{\n    //            y1 = y - 8;\n    //        }\n    //        for (unsigned char d = 0; d < 4; d++){\n    //            if (d == 0){\n    //                x1 = x - 8;\n    //                z1 = z - 8;\n    //            }else if (d==1){\n    //                x1 = x + 8;\n    //                z1 = z - 8;\n    //            }else if (d==2){\n    //                x1 = x - 8;\n    //                z1 = z + 8;\n    //            }else if (d==3){\n    //                x1 = x + 8;\n    //                z1 = z + 8;\n    //            }\n    //            //same thing, check if the player is inside the intersection\n    //            if ((boxX + 8) < ABS(playerPos->x - x1)) continue;\n    //            if ((boxY + 8) < ABS(playerPos->y + yPosOffset - y1)) continue;\n    //            if ((boxZ + 8) < ABS(playerPos->z - z1)) continue;\n    //            for (unsigned char l = 0; l < 2; l++){ //first subdivide\n    //                if (l == 0){\n    //                    y2 = y1 + 4;\n    //                }else{\n    //                    y2 = y1 - 4;\n    //                }\n    //                for (unsigned char j = 0; j < 4; j++){\n    //                    if (j == 0){\n    //                        x2 = x1 - 4;\n    //                        z2 = z1 - 4;\n    //                    }else if (j==1){\n    //                        x2 = x1 + 4;\n    //                        z2 = z1 - 4;\n    //                    }else if (j==2){\n    //                        x2 = x1 - 4;\n    //                        z2 = z1 + 4;\n    //                    }else if (j==3){\n    //                        x2 = x1 + 4;\n    //                        z2 = z1 + 4;\n    //                    }\n\n    //                    if ((boxX + 4) < ABS(playerPos->x - x2)) continue;\n    //                    if ((boxY + 4) < ABS(playerPos->y + yPosOffset - y2)) continue;\n    //                    if ((boxZ + 4) < ABS(playerPos->z - z2)) continue;\n\n    //                    for (unsigned char l2 = 0; l2 < 2; l2++){//second subdivide\n    //                        if (l2 == 0){\n    //                            y3 = y2 + 2;\n    //                        }else{\n    //                            y3 = y2 - 2;\n    //                        }\n\n    //                        for (unsigned char k = 0; k < 4; k++){\n    //                            if (k == 0){\n    //                                x3 = x2 - 2;\n    //                                z3 = z2 - 2;\n    //                            }else if (k==1){\n    //                                x3 = x2 + 2;\n    //                                z3 = z2 - 2;\n    //                            }else if (k==2){\n    //                                x3 = x2 - 2;\n    //                                z3 = z2 + 2;\n    //                            }else if (k==3){\n    //                                x3 = x2 + 2;\n    //                                z3 = z2 + 2;\n    //                            }\n    //                            if ((boxX + 2) < ABS(playerPos->x - x3)) continue;\n    //                            if ((boxY + 2) < ABS(playerPos->y + yPosOffset - y3)) continue;\n    //                            if ((boxZ + 2) < ABS(playerPos->z - z3)) continue;\n    //                            \n    //                            for (unsigned char l3 = 0; l3 < 2; l3++){ //third subdivide\n    //                                if (l3 == 0){\n    //                                    y4 = y3 + 1;\n    //                                }else{\n    //                                    y4 = y3 - 1;\n    //                                }\n    //                                for (unsigned char m = 0; m < 4; m++){\n    //                                    if (m == 0){\n    //                                        x4 = x3 - 1;\n    //                                        z4 = z3 - 1;\n    //                                    }else if (m==1){\n    //                                        x4 = x3 + 1;\n    //                                        z4 = z3 - 1;\n    //                                    }else if (m==2){\n    //                                        x4 = x3 - 1;\n    //                                        z4 = z3 + 1;\n    //                                    }else if (m==3){\n    //                                        x4 = x3 + 1;\n    //                                        z4 = z3 + 1;\n    //                                    }\n    //                                    if ((boxX + 1) < ABS(playerPos->x - x4)) continue;\n    //                                    if ((boxY + 1) < ABS(playerPos->y + yPosOffset - y4)) continue; \n    //                                    if ((boxZ + 1) < ABS(playerPos->z - z4)) continue;\n\n    //                                    for (unsigned char l4 = 0; l4 < 2; l4++){ //final subdivide. Check if the player is intersecting a block\n    //                                        if (l4 == 0){\n    //                                            y5 = y4 + 0.5;\n    //                                        }else{\n    //                                            y5 = y4 - 0.5;\n    //                                        }\n\n    //                                        for (unsigned char n = 0; n < 4; n++){\n    //                                            if (n == 0){\n    //                                                x5 = x4 - 0.5;\n    //                                                z5 = z4 - 0.5;\n    //                                            }else if (n==1){\n    //                                                x5 = x4 + 0.5;\n    //                                                z5 = z4 - 0.5;\n    //                                            }else if (n==2){\n    //                                                x5 = x4 - 0.5;\n    //                                                z5 = z4 + 0.5;\n    //                                            }else if (n==3){\n    //                                                x5 = x4 + 0.5;\n    //                                                z5 = z4 + 0.5;\n    //                                            }\n    //            \n    //                                            //find the distance from the players midpoint to the block's midpoint.\n    //                                            dx = playerPos->x - x5;\n    //                                            dy = playerPos->y + yPosOffset - y5;\n    //                                            dz = playerPos->z - z5;\n\n    //                                            if ((boxX + 0.5) < ABS(dx)) continue;\n    //                                            if ((boxY + 0.5) < ABS(dy)) continue; \n    //                                            if ((boxZ + 0.5) < ABS(dz)) continue;\n\n    //                                            int blx, bly, blz;\n    //                                            bool moveUp = 1;\n    //                                            \n    //                                            //finds the block coordinate location in the chunk\n    //                                            double tmp = CHUNK_WIDTH/2.0 - 0.5;\n    //                                            blx = (int)(x5 - (x - tmp));\n    //                                            bly = (int)(CHUNK_LAYER * (y5 - (y - tmp)));\n    //                                            blz = (int)(CHUNK_WIDTH * (z5 - (z - tmp)));\n\n    //                                            //finds the depth of collision. Higher value means deeper collision. Must reference dx dy and dz\n    //                                            //for direction. Substracts the length of both bounding boxes by the distance between to get the\n    //                                            //difference.\n    //                                            bdx = (double)(0.5+boxX) - ABS(dx);\n    //                                            bdy = (double)(0.5+boxY) - ABS(dy);\n    //                                            bdz = (double)(0.5+boxZ) - ABS(dz);\n\n    //                                            c = blx + bly + blz;\n    //                                            chunk = chunks[i];\n    //                                            if (chunk->isAccessible == false) continue;\n\n    //                                            blockID = chunk->getBlockIDSafe(lockedChunk, c);\n\n    //                                            if (blockID){\n    //                                                blockCollision(player, lockedChunk, chunks[i], blockID, c, bdx, bdy, bdz, dx, dy, dz);\n    //                                            }\n    //                                        }\n    //                                    }\n    //                                }\n    //                            }\n    //                        }\n    //                    }\n    //                }\n    //            }\n    //        }\n    //    }\n    //}\n    //if (lockedChunk) lockedChunk->unlock();\n}\n\n// TODO(Ben): What the FUCK is this?!?! This code is rated XXX.\nvoid blockCollision(Player *player VORB_UNUSED, Chunk* chunk VORB_UNUSED, Chunk*  lockedChunk VORB_UNUSED, GLushort blockType VORB_UNUSED, int c VORB_UNUSED, double bdx VORB_UNUSED, double bdy VORB_UNUSED, double bdz VORB_UNUSED, double dx VORB_UNUSED, double dy VORB_UNUSED, double dz VORB_UNUSED)\n{\n//    if (chunks[i]->data[blx + bly + blz] == WATER) continue; //no clip water\n\n//    f64v3 *playerPos = &(player->gridPosition);\n//    double boxX = player->boundingBox.x;\n//    double boxY = player->boundingBox.y/2.0;\n//    double boxZ = player->boundingBox.z;\n//    double stepMod = 1.0f/(float)PLAYER_COLLISION_STEPS;\n//    bool pushedDown = 0;\n//    CollisionData *cData = &(player->collisionData);\n//\n//    if (blockType >= LOWWATER){\n//    //    cout << (player->headPosition.y - player->position.y) << \"  \" << dy-(blockType - LOWWATER)*0.005 << endl;\n//        if (dy <= 0) player->isSwimming = 1;\n//    //    if (dy-(blockType - LOWWATER)*0.005 <= -(player->headPosition.y - player->position.y)) player->underWater = 1;\n//        if (dy+0.5 < -(player->headPosition.y - player->gridPosition.y - boxY - (blockType - LOWWATER)*0.01)) player->isUnderWater = 1;\n//    }\n//\n//    //cout << dx << \" \" << dy << \" \" << dz << \" \" << bdx << \" \" << bdy << \" \" << bdz << endl;\n//    if (Blocks[blockType].moveMod <= 1.0){\n//        if (Blocks[blockType].moveMod < player->getMoveMod()) player->setMoveMod(Blocks[blockType].moveMod);\n//    }\n//    else if (player->getMoveMod() >= 1.0){ //slippery things like ice\n//        if (Blocks[blockType].moveMod > player->getMoveMod()) player->setMoveMod(Blocks[blockType].moveMod);\n//    }\n//    //player->moveMod *= pow(Blocks[blockType].moveMod, stepMod);\n//    if (Blocks[blockType].collide == 0 || player->isFlying) return; //do no collision with the block\n//\n//    double mov = 0.07 * glSpeedFactor * stepMod; //mov is the distance we should move from a collision\n//    double push = 0.9 * stepMod;//how hard the block tries to push us out. Start with an almost full push. Dont set to 1.0 or it pushes too far and we climb jerkily\n//    bool moveUp = 0;    \n//    bool collided = 0;\n//\n//    if (dy >= 1.0) { //if the player is more than 1.0 block above a block\n//        NChunk* own;\n//        int nc;\n//        int topc = vvox::getTopBlockData(chunk, lockedChunk, c, nc, own);\n//        if (GETBLOCK(topc).collide == 0 && GETBLOCK(vvox::getTopBlockData(own, lockedChunk, nc)).collide == 0) { // if there is at least 2 free spaces above\n//    //        cout << \"TOP: \" << chunk->GetTopBlock(c) << \" \" << (int)GETBLOCK(chunk->GetTopBlock(c)).collide << \" \";\n//            moveUp = 1;\n//            push = 0.1 * stepMod; //if its a low climb, we can sorta clip into it\n//        }\n//    }else if (dy > -2.0 && dy < 1.0){\n//        player->canCling = 1;\n//        if (player->isSprinting) { //climbing happens when sprinting or holding jump\n//            if (GETBLOCK(vvox::getTopBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                moveUp = 1;\n//                player->isClinging = 1;\n//            }\n//        }\n//    }\n//\n//    if (player->isSprinting){\n//        mov = 0.1 * glSpeedFactor * stepMod;\n//    }\n//\n//    if (moveUp){\n//        if (bdy < mov){ //just a normal top of the block collision\n//            if (bdy > cData->yMove) cData->yMove = bdy;\n//            if (player->velocity.y < 0.0f){\n//                if (-player->velocity.y > cData->yDecel) cData->yDecel = -player->velocity.y;\n//                player->velocity.y = 0.0f;\n//            }\n//            if (bdx > 0.2 && bdz > 0.2){\n//                player->isGrounded = 1;\n//            }\n//        }else{ //climbing collision\n//            if (mov > cData->yMove) cData->yMove = mov;\n//            if (player->velocity.y < 0.0f){\n//                if (-player->velocity.y > cData->yDecel) cData->yDecel = -player->velocity.y;\n//                player->velocity.y = 0.0f;\n//            }\n//            player->isClimbing = 1;\n//        }\n//    }\n//\n//    if (bdy < bdz && bdy < bdx && dy < -0.5 && Blocks[GETBLOCKID(vvox::getBottomBlockData(chunk, lockedChunk, c))].collide == 0) { //head y collision\n//         //TODO PREVENT A FAST MOVING PERSON FROM GOING THROUGH BOTTOM BY TESTING HOW MUCH WE CAN CROUCH BEFORE WE BOUNCE OFF\n//    //    cout << \"A\";\n//        if (bdy > cData->headSquish) cData->headSquish = bdy; \n//        if (player->velocity.y > 0.0f) player->velocity.y = 0.0; //maybe not do this? let people hit their heads and feet scrunch up\n//    }\n//    if (bdx < bdz && bdy > 0.2){ //x collision BDY is different when crouching. Look into this\n//        if (!player->isSprinting  && GETBLOCK(vvox::getBottomBlockData(chunk, lockedChunk, c)).collide == 0) { //auto crouch\n//            if (player->getCrouch() != 1.0){\n//                if (dx < 0 && GETBLOCK(vvox::getLeftBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                    pushedDown = 1;\n//                } else if (dx > 0 && GETBLOCK(vvox::getRightBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                    pushedDown = 1;\n//                }\n//            }\n//            if (pushedDown && !player->isClinging){\n//                collided = 1; //to stop z from colliding\n//                mov = 0.2 * glSpeedFactor * stepMod;\n//                if (mov > bdy - 0.2) mov = bdy - 0.2;\n//                if (mov > cData->headSquish) cData->headSquish = mov; \n//    //            cout << \"G \" << (int)player->clinging;\n//            }\n//            //if (player->velocity.y > 0.0f) player->velocity.y = 0.0; \n//        }\n//        if (!pushedDown || dy > -0.2){\n//            if (dx > 0 && GETBLOCK(vvox::getRightBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                mov = bdx*push;\n//                if (mov > ABS(cData->xMove)) cData->xMove = mov;\n//                collided = 1;\n//    //            cout << \"C\";\n//            } else if (GETBLOCK(vvox::getLeftBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                mov = bdx*push;\n//                if (mov > ABS(cData->xMove)) cData->xMove = -mov;\n//                collided = 1;\n////                cout << \"C\";\n//            }\n//        }\n//        if ((1.0 - push) < cData->xPush) cData->xPush = 1.0 - push;\n//    }\n//    if (bdy > 0.2 && !collided){ //z collision\n//        if (!player->isSprinting && dy < -0.0 && GETBLOCK(vvox::getBottomBlockData(chunk, lockedChunk, c)).collide == 0) { //auto crouch\n//            if (player->getCrouch() != 1.0){\n//                if (dz < 0 && GETBLOCK(vvox::getBackBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                    pushedDown = 1;\n//                } else if (dz > 0 && GETBLOCK(vvox::getFrontBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                    pushedDown = 1;\n//                }\n//            }\n//            if (pushedDown && !player->isClinging){\n//    //            cout << \"A \";\n//                mov = 0.2 * glSpeedFactor * stepMod;\n//                if (mov > bdy - 0.2) mov = bdy - 0.2;\n//                if (mov > cData->headSquish) cData->headSquish = mov; \n//            }\n//            //if (player->velocity.y > 0.0f) player->velocity.y = 0.0; \n//        }\n//        if (!pushedDown || dy > -0.2){\n//            if (dz > 0 && GETBLOCK(vvox::getFrontBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                mov = bdz*push;\n//                if (mov > ABS(cData->zMove)) cData->zMove = mov;\n//    //            cout << \"B\";\n//            } else if (GETBLOCK(vvox::getBackBlockData(chunk, lockedChunk, c)).collide == 0) {\n//                mov = bdz*push;\n//                if (mov > ABS(cData->zMove)) cData->zMove = -mov;\n//    //            cout << \"B\";\n//            }\n//        }\n//        if ((1.0 - push) < cData->zPush) cData->zPush = 1.0 - push;\n//    }\n}"
  },
  {
    "path": "SoA/Collision.h",
    "content": "#pragma once\n#include \"Vorb/types.h\"\n\nclass Player;\nclass Chunk;\n\nconst i32 PLAYER_COLLISION_STEPS = 20;\n\n//bool RaySphere(float xc, float yc, float zc, float xd, float yd, float zd, float xs, float ys, float zs, float r, float *dist=NULL, coordinate3lf *point=NULL);\n//bool RayPlane(float nx, float ny, float nz, float xs, float ys, float zs, float xd, float yd, float zd, coordinate3lf &p1, coordinate3lf &p2, coordinate3lf &p3, coordinate3lf &p4, float *dist=NULL, coordinate3lf *point=NULL);\n//bool SphereSphere(coordinate3lf &p1, coordinate3lf p2, float radius1, float radius2);\n//bool SpherePlane(coordinate3lf &sp, coordinate3lf &vn, coordinate3lf &p1, coordinate3lf &p2, coordinate3lf &p3, coordinate3lf &p4, float r);\n//float TriangleArea(coordinate3lf &p1, coordinate3lf &p2, coordinate3lf &p3);\n//bool AABBCollision(coordinate3lf &b1, coordinate3lf &b2, coordinate3lf &r1, coordinate3lf &r2, coordinate3lf &vn);\n\nvoid aabbChunkCollision(Player* player, f64v3* playerPos, Chunk** chunks, ui8 size);"
  },
  {
    "path": "SoA/CollisionComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"CollisionComponentUpdater.h\"\n\n#include \"GameSystem.h\"\n\nvoid CollisionComponentUpdater::update(GameSystem* gameSystem VORB_UNUSED) {\n    // for (auto& it : gameSystem->aabbCollidable) {\n         //TODO(Ben): this\n    // }\n}"
  },
  {
    "path": "SoA/CollisionComponentUpdater.h",
    "content": "///\n/// CollisionComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates collision components\n///\n\n#pragma once\n\n#ifndef CollisionComponentUpdater_h__\n#define CollisionComponentUpdater_h__\n\nclass GameSystem;\n\nclass CollisionComponentUpdater {\npublic:\n    /// Updates collision components\n    /// @param gameSystem: Game ECS\n    void update(GameSystem* gameSystem);\n};\n\n#endif // CollisionComponentUpdater_h__\n"
  },
  {
    "path": "SoA/ColorFilterRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ColorFilterRenderStage.h\"\n\n#include \"ShaderLoader.h\"\n\nnamespace {\n    const cString VERT_SRC = R\"(\nin vec4 vPosition;\nvoid main() {\n  gl_Position = vPosition;\n}\n)\";\n\n    const cString FRAG_SRC = R\"(\nuniform vec4 unColor;\nout vec4 pColor;\nvoid main() {\n  pColor = unColor;\n}\n)\";\n}\n\nvoid ColorFilterRenderStage::hook(vg::FullQuadVBO* quad) {\n    m_quad = quad;\n}\n\nvoid ColorFilterRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED /*= nullptr*/) {\n\n    if (!m_program.isCreated()) {\n        m_program = ShaderLoader::createProgram(\"ColorFilterShader\", VERT_SRC, FRAG_SRC);\n    }\n\n    m_program.use();\n\n    glUniform4fv(m_program.getUniform(\"unColor\"), 1, &m_color[0]);\n\n    glDisable(GL_DEPTH_TEST);\n    m_quad->draw();\n    glEnable(GL_DEPTH_TEST);\n\n    m_program.unuse();\n}\n"
  },
  {
    "path": "SoA/ColorFilterRenderStage.h",
    "content": "///\n/// ColorFilterRenderStage.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 25 Apr 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renders a full screen color filter\n///\n\n#pragma once\n\n#ifndef ColorFilterRenderStage_h__\n#define ColorFilterRenderStage_h__\n\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GLProgram.h>\n#include \"IRenderStage.h\"\n\nclass ColorFilterRenderStage : public IRenderStage {\npublic:\n    void hook(vg::FullQuadVBO* quad);\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera = nullptr) override;\n\n    void setColor(const f32v4& color) { m_color = color; }\nprivate:\n    f32v4 m_color;\n    vg::FullQuadVBO* m_quad = nullptr;\n    vg::GLProgram m_program;\n};\n\n#endif // ColorFilterRenderStage_h__\n"
  },
  {
    "path": "SoA/ColoredFullQuadRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ColoredFullQuadRenderer.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\nconst cString COL_VERT_SRC = R\"(\nin vec4 vPosition;\nvoid main() {\n    gl_Position = vPosition;\n}\n)\";\n\nconst cString COL_FRAG_SRC = R\"(\nuniform vec4 unColor;\nout vec4 fColor;\nvoid main() {\n    fColor = unColor;\n}\n)\";\n\nColoredFullQuadRenderer::~ColoredFullQuadRenderer() {\n    if (m_program) {\n        m_program->dispose();\n        delete m_program;\n    }\n}\n\nvoid ColoredFullQuadRenderer::draw(vg::FullQuadVBO& quad, const f32v4& color) {\n    // Lazy shader init\n    if (!m_program) {\n        m_program = new vg::GLProgram(true);\n\n        m_program->addShader(vg::ShaderType::VERTEX_SHADER, COL_VERT_SRC);\n        m_program->addShader(vg::ShaderType::FRAGMENT_SHADER, COL_FRAG_SRC);\n\n        m_program->link();\n        m_program->initUniforms();\n        m_program->initAttributes();\n    }\n    // Draw the quad\n    m_program->use();\n    m_program->enableVertexAttribArrays();\n    glUniform4fv(m_program->getUniform(\"unColor\"), 1, &color[0]);\n    quad.draw();\n    m_program->disableVertexAttribArrays();\n    m_program->unuse();\n}\n"
  },
  {
    "path": "SoA/ColoredFullQuadRenderer.h",
    "content": "///\n/// ColoredFullQuadRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 22 Mar 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renders a FullQuadVBO with color\n///\n\n#pragma once\n\n#ifndef ColoredFullQuadRenderer_h__\n#define ColoredFullQuadRenderer_h__\n\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/VorbPreDecl.inl>\n\nDECL_VG(class GLProgram);\n\nclass ColoredFullQuadRenderer {\npublic:\n    ~ColoredFullQuadRenderer();\n    void draw(vg::FullQuadVBO& quad, const f32v4& color);\nprivate:\n    vg::GLProgram* m_program = nullptr;\n};\n\n#endif // ColoredFullQuadRenderer_h__\n"
  },
  {
    "path": "SoA/CommonState.h",
    "content": "///\n/// CommonState.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 4 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Container for states and controllers passed between screens.\n///\n\n#pragma once\n\n#ifndef CommonState_h__\n#define CommonState_h__\n\n#include \"LoadContext.h\"\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/FullQuadVBO.h>\n\n#include \"SpaceSystemRenderStage.h\"\n#include \"SkyboxRenderStage.h\"\n#include \"HdrRenderStage.h\"\n\nstruct SoaState;\nDECL_VSOUND(class Engine)\nDECL_VUI(class GameWindow)\n\nstruct CommonState {\npublic:\n    SoaState* state = nullptr;\n    vsound::Engine* soundEngine = nullptr;\n    vui::GameWindow* window = nullptr;\n    StaticLoadContext loadContext;\n\n    struct {\n        SkyboxRenderStage skybox;\n        SpaceSystemRenderStage spaceSystem;\n        HdrRenderStage hdr;\n    } stages; // Shared render stages\n    vg::FullQuadVBO quad; ///< Quad used for post-processing\n};\n\n#endif // CommonState_h__\n"
  },
  {
    "path": "SoA/Computer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Computer.h\"\n\nComputer::Computer() {\n    // Empty\n}\nComputer::~Computer() {\n    // Empty\n}"
  },
  {
    "path": "SoA/Computer.h",
    "content": "// \n//  Computer.h\n//  Seed Of Andromeda\n//\n//  Created by Ben Arnold on 26 Oct 2014\n//  Copyright 2014 Regrowth Studios\n//  MIT License\n//  \n//  Summary:\n//  This file provides the implementation for a virtual computer.\n//\n\n#pragma once\n\n#ifndef Computer_h_\n#define Computer_h_\n\nclass Computer {\npublic:\n    Computer();\n    virtual ~Computer();\n};\n\n#endif // Computer_h_"
  },
  {
    "path": "SoA/ConsoleFuncs.h",
    "content": "//\n// ConsoleFuncs.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 30 Jun 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef ConsoleFuncs_h__\n#define ConsoleFuncs_h__\n\n#include <Vorb/types.h>\n#include <Vorb/script/IEnvironment.hpp>\n\n#include \"DLLAPI.h\"\n#include \"SoAState.h\"\n#include \"SoaController.h\"\n#include \"SoaEngine.h\"\n#include \"ConsoleTests.h\"\n\n#include <chrono>\n\ntemplate <typename ScriptImpl>\nvoid runScript(vscript::IEnvironment<ScriptImpl>* env, const cString file) {\n    env->run(nString(file));\n}\n\n#ifdef VORB_OS_WINDOWS\nint loadDLL(const cString name) {\n    HINSTANCE dll = LoadLibrary(name);\n    int(*f)() = (int(*)())GetProcAddress(dll, \"getCode\");\n    fflush(stderr);\n    fflush(stdout);\n    return f();\n}\n#endif//VORB_OS_WINDOWS\n\ntemplate<typename T>\nT* create() {\n    T* v = new T();\n    return v;\n}\ntemplate<typename T>\nvoid free(T* v) {\n    delete v;\n}\n\nvoid initState(SoaState* s, const cString spaceSystemDir) {\n    SoaEngine::initState(s);\n    SoaEngine::loadSpaceSystem(s, spaceSystemDir);\n}\n\nstd::thread* startGame(SoaState* s, SoaController* c) {\n    std::thread* t = new std::thread([=] () {\n        c->startGame(s);\n        while (true) {\n//            Sleep(100);\n            std::this_thread::sleep_for(std::chrono::milliseconds(100));\n        }\n        return;\n    });\n    return t;\n}\nvoid stopGame(std::thread* t) {\n    bool isRunning = true;\n    std::thread printer([&] () {\n        puts(\"\");\n        size_t i = 2;\n        char buf[] = { '\\r', '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ' , '\\0' };\n        while (isRunning) {\n            puts(buf);\n            i++;\n            buf[i] = ' ';\n            i %= 8;\n            buf[i + 1] = '.';\n//            Sleep(250);\n            std::this_thread::sleep_for(std::chrono::milliseconds(250));\n        }\n    });\n    t->join();\n    isRunning = false;\n    delete t;\n}\n\nvoid setStartingPlanet(SoaState* s, vecs::EntityID eID) {\n    s->clientState.startingPlanet = eID;\n}\n\ntemplate <typename ScriptImpl>\nvoid registerFuncs(vscript::IEnvironment<ScriptImpl>* env) {\n    env->setNamespaces(\"SC\");\n\n    /************************************************************************/\n    /* Application methods                                                  */\n    /************************************************************************/\n    env->addValue(\"env\", env);\n    env->addCDelegate(\"run\", makeDelegate(runScript<ScriptImpl>));\n#ifdef VORB_OS_WINDOWS\n    env->addCDelegate(\"loadDLL\", makeDelegate(loadDLL));\n#endif//VORB_OS_WINDOWS\n\n    /************************************************************************/\n    /* Game-specific methods                                                */\n    /************************************************************************/\n    env->addCDelegate(\"createState\",       makeDelegate(create<SoaState>));\n    env->addCDelegate(\"freeState\",         makeDelegate(free<SoaState>));\n    env->addCDelegate(\"createController\",  makeDelegate(create<SoaController>));\n    env->addCDelegate(\"freeController\",    makeDelegate(free<SoaController>));\n    env->addCDelegate(\"initState\",         makeDelegate(initState));\n    env->addCDelegate(\"startGame\",         makeDelegate(startGame));\n    env->addCDelegate(\"stopGame\",          makeDelegate(stopGame));\n    env->addCDelegate(\"setStartingPlanet\", makeDelegate(setStartingPlanet));\n\n    /************************************************************************/\n    /* Test methods                                                         */\n    /************************************************************************/\n    env->setNamespaces(\"CAS\");\n    env->addCDelegate(\"create\", makeDelegate(createCASData));\n    env->addCDelegate(\"run\",    makeDelegate(runCAS));\n    env->addCDelegate(\"free\",   makeDelegate(freeCAS));\n\n    env->setNamespaces(\"CHS\");\n    env->addCDelegate(\"run\", makeDelegate(runCHS));\n\n    env->setNamespaces();\n}\n\n#endif // ConsoleFuncs_h__\n"
  },
  {
    "path": "SoA/ConsoleMain.h",
    "content": "//\n// ConsoleMain.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 29 Jun 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Main entry point for the console version of the application.\n//\n\n#pragma once\n\n#ifndef ConsoleMain_h__\n#define ConsoleMain_h__\n\n#include <Vorb/script/IEnvironment.hpp>\n#include <Vorb/script/ConsoleBackend.hpp>\n\n#include \"ConsoleFuncs.h\"\n\n#ifdef VORB_OS_WINDOWS\n#define SOA_CONSOLE_COLOR_HEADER (FOREGROUND_BLUE | FOREGROUND_INTENSITY)\n#define SOA_CONSOLE_COLOR_PROMPT (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY)\n#define SOA_CONSOLE_COLOR_MAIN (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)\n#define SOA_CONSOLE_COLOR_OUTPUT (FOREGROUND_GREEN | FOREGROUND_INTENSITY)\n#define SOA_CONSOLE_COLOR_ERROR (FOREGROUND_RED | FOREGROUND_INTENSITY)\n#else//VORB_OS_WINDOWS\n#define SOA_CONSOLE_COLOR_HEADER 34\n#define SOA_CONSOLE_COLOR_PROMPT 33\n#define SOA_CONSOLE_COLOR_MAIN 37\n#define SOA_CONSOLE_COLOR_OUTPUT 32\n#define SOA_CONSOLE_COLOR_ERROR 31\n#endif//VORB_OS_WINDOWS\n\nnamespace {\n    struct ConsolePrinter {\n    public:\n        void setColor(ui32 color) {\n            if (m_lastColor != color) {\n                fflush(stdout);\n                fflush(stderr);\n            }\n            m_lastColor = color;\n#ifdef VORB_OS_WINDOWS\n            SetConsoleTextAttribute(hndConsole, color);\n#else\n            printf(\"\\033[0;%dm\", color);\n#endif//VORB_OS_WINDOWS            \n        }\n        void out(Sender, const cString msg) {\n            setColor(SOA_CONSOLE_COLOR_OUTPUT);\n            puts(msg);\n        }\n        void err(Sender, const cString msg) {\n            setColor(SOA_CONSOLE_COLOR_ERROR);\n            puts(msg);\n        }\n\n#ifdef VORB_OS_WINDOWS\n        HANDLE hndConsole;\n#endif//VORB_OS_WINDOWS\n\n    private:\n        ui32 m_lastColor = 0;\n    };\n}\n\ntemplate <typename ScriptImpl>\nvoid consoleMain() {\n    // Get console for manipulation\n    ConsolePrinter printer = {};\n\n#ifdef VORB_OS_WINDOWS\n    printer.hndConsole = GetStdHandle(STD_OUTPUT_HANDLE);\n#endif//VORB_OS_WINDOWS\n\n    // Write out that we are using the console version\n    printer.setColor(SOA_CONSOLE_COLOR_HEADER);\n    puts(R\"(\n     _________________\n    /                /\n   /                /\n  /  SoA Console   /\n /                / ______\n/                /  |v0.1|\n==========================\n)\");\n\n    vscript::IEnvironment<ScriptImpl>* env = new ScriptImpl();\n\n    vscript::ConsoleBackend<ScriptImpl> repl;\n    repl.init(env);\n\n    registerFuncs<ScriptImpl>(env);\n\n    repl.onConsoleOutput.out += makeDelegate(&printer, &ConsolePrinter::out);\n    repl.onConsoleOutput.err += makeDelegate(&printer, &ConsolePrinter::err);\n\n    char buf[1024];    \n    while (true) {\n        printer.setColor(SOA_CONSOLE_COLOR_PROMPT);\n        printf(\">>> \");\n        printer.setColor(SOA_CONSOLE_COLOR_MAIN);\n        std::cin.getline(buf, 1024);\n        repl.invokeCommand(buf);\n    }\n\n    delete env;\n}\n\n#endif // ConsoleMain_h__\n"
  },
  {
    "path": "SoA/ConsoleTests.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ConsoleTests.h\"\n\n#include \"ChunkAllocator.h\"\n#include \"ChunkAccessor.h\"\n\n#include <random>\n#include <Vorb/Timing.h>\n\nstruct ChunkAccessSpeedData {\n    size_t numThreads;\n    std::thread* threads;\n\n    std::mutex lock;\n    std::condition_variable cv;\n\n    PagedChunkAllocator allocator;\n    ChunkAccessor accessor;\n\n    ChunkID* ids;\n    ChunkHandle* handles;\n};\n\nChunkAccessSpeedData* createCASData(size_t numThreads, size_t requestCount, ui64 maxID) {\n    ChunkAccessSpeedData* data = new ChunkAccessSpeedData;\n\n    data->accessor.init(&data->allocator);\n\n    // Create the thread pools\n    data->numThreads = numThreads;\n    data->threads = new std::thread[numThreads] {};\n    for (size_t threadID = 0; threadID < numThreads; threadID++) {\n        std::thread([data, threadID, requestCount] () {\n            { // Wait until everyone is notified\n                std::unique_lock<std::mutex> lock(data->lock);\n                printf(\"Thread %zu awaiting notification\\n\", threadID);\n                data->cv.wait(lock);\n            }\n\n            std::mt19937 rEngine(threadID);\n            std::uniform_int_distribution<int> release(0, 1);\n\n            // Begin requesting chunks\n            printf(\"Thread %zu starting\\n\", threadID);\n            PreciseTimer timer;\n            timer.start();\n            ChunkID* id = data->ids + (requestCount * threadID);\n            ChunkHandle* hndAcquire = data->handles + (requestCount * threadID);\n            ChunkHandle* hndRelease = hndAcquire;\n            ChunkHandle* hndEnd = hndRelease + requestCount;\n            while (hndRelease != hndEnd) {\n                if ((hndAcquire > hndRelease) && release(rEngine)) {\n                    // Release a handle\n                    hndRelease->release();\n                    hndRelease++;\n                } else if(hndAcquire != hndEnd) {\n                    // Acquire a handle\n                    *hndAcquire = data->accessor.acquire(*id);\n                    hndAcquire++;\n                    id++;\n                }\n            }\n            printf(\"Thread %zu finished in %lf ms\\n\", threadID, timer.stop());\n        }).swap(data->threads[threadID]);\n        data->threads[threadID].detach();\n    }\n\n    // Create the random requests\n    data->ids = new ChunkID[requestCount * numThreads];\n    data->handles = new ChunkHandle[requestCount * numThreads]{};\n    for (size_t i = 0; i < requestCount * numThreads; i++) {\n        data->ids[i] = rand() % maxID;\n    }\n\n    return data;\n}\n\nvoid runCAS(ChunkAccessSpeedData* data) {\n    // Start the races\n    data->cv.notify_all();\n}\n\nvoid freeCAS(ChunkAccessSpeedData* data) {\n    printf(\"Chunks Alive: %zu\\n\", data->accessor.getCountAlive());\n    fflush(stdout);\n    data->accessor.destroy();\n    delete[] data->ids;\n    delete[] data->handles;\n    delete[] data->threads;\n    delete data;\n}\n\nvoid runCHS() {\n    PagedChunkAllocator allocator = {};\n    ChunkAccessor accessor = {};\n    accessor.init(&allocator);\n\n\n    ChunkHandle h1 = accessor.acquire(1);\n    ChunkHandle h2 = h1;\n    h2 = h2.acquire();\n    h2.release();\n    h1.release();\n}\n"
  },
  {
    "path": "SoA/ConsoleTests.h",
    "content": "//\n// ConsoleTests.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 1 Aug 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef ConsoleTests_h__\n#define ConsoleTests_h__\n\n#include \"Chunk.h\"\n\n/************************************************************************/\n/* Chunk Access Speed                                                   */\n/************************************************************************/\nstruct ChunkAccessSpeedData;\nChunkAccessSpeedData* createCASData(size_t numThreads, size_t requestCount, ui64 maxID);\nvoid runCAS(ChunkAccessSpeedData* data);\nvoid freeCAS(ChunkAccessSpeedData* data);\n\nvoid runCHS();\n\n#endif // !ConsoleTests_h__\n"
  },
  {
    "path": "SoA/Constants.h",
    "content": "///\n/// Constants.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 17 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Defines helpful SoA specific constants\n///\n\n#pragma once\n\n#ifndef Constants_h__\n#define Constants_h__\n\n#define SOA_VERSION 0.1.5\n\n#ifdef _DEBUG \n#define _CRTDBG_MAP_ALLOC\n#include <cstdlib>\n#include <crtdbg.h>\n#endif\n\n#include <Vorb/math/VorbMath.hpp>\n\n// Uncomment for advanced heap checking\n#ifdef _DEBUG\n//#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) \n//#define new DEBUG_NEW\n#endif\n\nconst i32 CHUNK_WIDTH = 32;\n// Chunk Width Minus 1\nconst i32 CHUNK_WIDTH_M1 = 31;\nconst i32 HALF_CHUNK_WIDTH = CHUNK_WIDTH / 2;\nconst i32 CHUNK_LAYER = CHUNK_WIDTH*CHUNK_WIDTH;\nconst i32 CHUNK_SIZE = CHUNK_LAYER*CHUNK_WIDTH;\nconst i32 SURFACE_DEPTH = 256;\nconst i32 OBJECT_LIST_SIZE = 24096;\n\n#define M_SOL 1989100000000000000000000000000.0\n\n/*** Helpful conversion factors ***/\nconst f64 KM_PER_M = 0.001;\nconst f64 M_PER_KM = 1000.0;\nconst f64 KM_PER_VOXEL = 0.0005;\nconst f64 M_PER_VOXEL = 0.5;\nconst f64 VOXELS_PER_M = 2.0;\nconst f64 VOXELS_PER_KM = 2000.0;\n\n// Useful sentinal value to use in place of DBL_MAX for distance checks and such,\n// since DBL_MAX is just too damn big and can overflow with any math\nconst f64 DOUBLE_SENTINEL = 10000000000000000000000000000000000000000000.0;\n\nconst f64 DEG_TO_RAD = M_PI / 180.0;\n\n#define BIT(i) (1 << (i))\n\n#endif // Constants_h__\n"
  },
  {
    "path": "SoA/CutoutVoxelRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"CutoutVoxelRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"BlockPack.h\"\n#include \"BlockTexturePack.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkRenderer.h\"\n#include \"GameRenderParams.h\"\n#include \"SoaOptions.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n\nvoid CutoutVoxelRenderStage::hook(ChunkRenderer* renderer, const GameRenderParams* gameRenderParams) {\n    m_renderer = renderer;\n    m_gameRenderParams = gameRenderParams;\n}\n\nvoid CutoutVoxelRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    ChunkMeshManager* cmm = m_gameRenderParams->chunkMeshmanager;\n    \n\n    const f64v3& position = m_gameRenderParams->chunkCamera->getPosition();\n\n    m_renderer->beginCutout(m_gameRenderParams->blockTexturePack->getAtlasTexture(), m_gameRenderParams->sunlightDirection,\n                            m_gameRenderParams->sunlightColor);\n\n    glDisable(GL_CULL_FACE);\n\n    // f64v3 cpos;\n\n    // TODO: Implement the saving mechanism/throw it out.\n    // static GLuint saveTicks = SDL_GetTicks();\n    // bool save = 0;\n    // if (SDL_GetTicks() - saveTicks >= 60000) { //save once per minute\n    //     save = 1;\n    //     saveTicks = SDL_GetTicks();\n    // }\n\n    ChunkMesh *cm;\n\n    const std::vector <ChunkMesh *>& chunkMeshes = cmm->getChunkMeshes();\n    {\n        std::lock_guard<std::mutex> l(cmm->lckActiveChunkMeshes);\n        if (chunkMeshes.empty()) return;\n        for (int i = chunkMeshes.size() - 1; i >= 0; i--) {\n            cm = chunkMeshes[i];\n\n            if (cm->inFrustum) {\n                m_renderer->drawCutout(cm, position,\n                                       m_gameRenderParams->chunkCamera->getViewProjectionMatrix());\n            }\n        }\n    }\n    glEnable(GL_CULL_FACE);\n    \n    m_renderer->end();\n}\n\n"
  },
  {
    "path": "SoA/CutoutVoxelRenderStage.h",
    "content": "/// \n///  CutoutVoxelRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the render stage for cutout voxels.\n///  cutout voxels have pixels that are either fully opaque, or\n///  fully transparent, and it's shader uses glDiscard to discard\n///  transparent fragments.\n///\n\n#pragma once\n\n#ifndef CutoutVoxelRenderStage_h__\n#define CutoutVoxelRenderStage_h__\n\n#include \"IRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\nclass Camera;\nclass ChunkRenderer;\nclass GameRenderParams;\nclass MeshManager;\n\nclass CutoutVoxelRenderStage : public IRenderStage {\npublic:\n    void hook(ChunkRenderer* renderer, const GameRenderParams* gameRenderParams);\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera) override;\nprivate:\n    ChunkRenderer* m_renderer;\n    const GameRenderParams* m_gameRenderParams; ///< Handle to some shared parameters\n};\n\n#endif // CutoutVoxelRenderStage_h__"
  },
  {
    "path": "SoA/DLLAPI.h",
    "content": "//\n// DLLAPI.h\n//\n\n#pragma once\n\n#ifndef DLLAPI_h__\n\nnamespace DLLAPI {\n    struct Information {\n        const cString name; ///< The name of the DLL\n        const cString friendlyName; ///< A human readable form of the DLL\n\n        union {\n            struct {\n                i32 major : 8;\n                i32 minor : 12;\n                i32 revision : 12;\n            };\n            i32 id;\n        } version; ///< Versioning information\n    };\n\n    typedef void (*FuncRetrieveInformation)(DLLAPI::Information* info);\n    typedef void (*FuncFillFuntionTable)(void*** table, size_t* count);\n\n}\n\n#endif // DLLAPI_h__\n"
  },
  {
    "path": "SoA/DLLLoader.h",
    "content": "//\n// DLLLoader.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 4 Jul 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef DLLLoader_h__\n#define DLLLoader_h__\n\n\n\n#endif // DLLLoader_h__\n"
  },
  {
    "path": "SoA/DebugRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"DebugRenderer.h\"\n\n#include <algorithm>\n#include <functional>\n\n#include <Vorb/MeshGenerators.h>\n#include <Vorb/graphics/RasterizerState.h>\n#include <Vorb/graphics/ShaderManager.h>\n\n#include \"GameManager.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n\nnamespace {\n    const cString VERT_SRC = R\"(\n// Uniforms\nuniform mat4 unWVP;\n\n// Input\nin vec4 vPosition; // Position in object space\nin vec4 vColor;\n\nout vec4 fColor;\n\nvoid main() {\n  fColor = vColor;\n  gl_Position = unWVP * vPosition;\n}\n)\";\n    const cString FRAG_SRC = R\"(\nin vec4 fColor;\n\n// Output\nout vec4 pColor;\n\nvoid main() {\n  pColor = fColor;\n}\n\n)\";\n}\n\nf32v3 findMidpoint(f32v3 vertex1, f32v3 vertex2);\n\nclass Vec3KeyFuncs {\npublic:\n    size_t operator()(const f32v3& k)const {\n        return std::hash<float>()(k.x) ^ std::hash<float>()(k.y) ^ std::hash<float>()(k.z);\n    }\n\n    bool operator()(const f32v3& a, const f32v3& b)const {\n        return a.x == b.x && a.y == b.y && a.z == b.z;\n    }\n};\n\nDebugRenderer::~DebugRenderer() {\n   \n    if (m_program.isCreated()) {\n        m_program.dispose();\n        glDeleteBuffers(1, &m_vbo);\n        glDeleteBuffers(1, &m_ibo);\n    }\n}\n\nvoid DebugRenderer::render(const f32m4 &vp, const f64v3& playerPos, const f32m4& w /* = f32m4(1.0) */) {\n\n    vg::RasterizerState::CULL_NONE.set();\n\n    m_previousTimePoint = m_currentTimePoint;\n    m_currentTimePoint = std::chrono::high_resolution_clock::now();\n    std::chrono::duration<double> elapsedTime = m_currentTimePoint - m_previousTimePoint;\n    double deltaT = elapsedTime.count();\n\n    if (!m_program.isCreated()) {\n        m_program = ShaderLoader::createProgram(\"DebugRenderer\", VERT_SRC, FRAG_SRC);\n        glGenBuffers(1, &m_vbo);\n        glGenBuffers(1, &m_ibo);\n    }\n\n    m_program.use();\n    m_program.enableVertexAttribArrays();\n    \n    for (auto& c : m_contexts) {\n     //   if (c.second.icospheres.size()) renderIcospheres(c.second.icospheres, vp, w, playerPos, deltaT);\n     //   if (c.second.cubes.size()) renderCubes(c.second.cubes, vp, w, playerPos, deltaT);\n        if (c.second.lines.size()) renderLines(c.second.lines, vp, w, playerPos, deltaT);\n    }\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    \n    m_program.disableVertexAttribArrays();\n    m_program.use();\n    \n}\n\nvoid DebugRenderer::drawIcosphere(const f64v3 &position, const float radius, const color4 &color, const int lod, ui32 context /*= 0*/, const double duration) {\n    auto lookup = m_icosphereMeshes.find(lod);\n    if(lookup == m_icosphereMeshes.end()) {\n        createIcosphere(lod);\n    }\n    Icosphere sphere;\n    sphere.color = color;\n    sphere.lod = lod;\n    sphere.position = position;\n    sphere.radius = radius;\n    sphere.timeTillDeletion = duration;\n    m_contexts[context].icospheres.push_back(sphere);\n}\n\nvoid DebugRenderer::drawCube(const f64v3 &position, const f64v3 &size, const color4 &color, ui32 context /*= 0*/, const double duration) {\n\n    Cube cube;\n    cube.position = position;\n    cube.size = size;\n    cube.color = color;\n    cube.timeTillDeletion = duration;\n    m_contexts[context].cubes.push_back(cube);\n}\n\nvoid DebugRenderer::drawLine(const f64v3 &startPoint, const f64v3 &endPoint, const color4 &color, ui32 context /*= 0*/, const double duration) {\n    Line line;\n    line.color = color;\n    line.position1 = startPoint;\n    line.position2 = endPoint;\n    line.timeTillDeletion = duration;\n    m_contexts[context].lines.push_back(line);\n}\n\nvoid DebugRenderer::renderIcospheres(std::vector<Icosphere>& icospheres VORB_UNUSED, const f32m4 &vp VORB_UNUSED, const f32m4& w VORB_UNUSED, const f64v3& playerPos VORB_UNUSED, const double deltaT VORB_UNUSED) {\n   /* f32m4 modelMatrix(1.0f);\n    for (auto i = icospheres.begin(); i != icospheres.end(); i++) {\n        SimpleMesh* mesh = m_icosphereMeshes.at(i->lod);\n        glBindBuffer(GL_ARRAY_BUFFER, mesh->vertexBufferID);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->indexBufferID);\n        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(f32v3), 0);\n\n        setMatrixTranslation(modelMatrix, i->position, playerPos);\n        setMatrixScale(modelMatrix, i->radius);\n        f32m4 mvp = vp * modelMatrix * w;\n\n        glUniform4f(m_program.getUniform(\"unColor\"), i->color.r, i->color.g, i->color.b, i->color.a);\n        glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, GL_FALSE, &mvp[0][0]);\n        glDrawElements(GL_TRIANGLES, mesh->numIndices, GL_UNSIGNED_INT, 0);\n\n        i->timeTillDeletion -= deltaT;\n    }\n\n    icospheres.erase(std::remove_if(icospheres.begin(), icospheres.end(), [](const Icosphere& sphere) { return sphere.timeTillDeletion <= 0; }), icospheres.end());*/\n}\n\nvoid DebugRenderer::renderCubes(std::vector<Cube>& cubes VORB_UNUSED, const f32m4 &vp VORB_UNUSED, const f32m4& w VORB_UNUSED, const f64v3& playerPos VORB_UNUSED, const double deltaT VORB_UNUSED) {\n  /*  glBindBuffer(GL_ARRAY_BUFFER, m_cubeMesh->vertexBufferID);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_cubeMesh->indexBufferID);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(f32v3), 0);\n    f32m4 modelMatrix(1.0f);\n    for (auto i = cubes.begin(); i != cubes.end(); i++) {\n        setMatrixTranslation(modelMatrix, i->position, playerPos);\n        setMatrixScale(modelMatrix, i->size);\n        f32m4 mvp = vp * modelMatrix * w;\n\n        glUniform4f(m_program.getUniform(\"unColor\"), i->color.r, i->color.g, i->color.b, i->color.a);\n        glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, GL_FALSE, &mvp[0][0]);\n\n        glDrawElements(GL_TRIANGLES, m_cubeMesh->numIndices, GL_UNSIGNED_INT, 0);\n\n        i->timeTillDeletion -= deltaT;\n    }\n    cubes.erase(std::remove_if(_cubesToRender.begin(), _cubesToRender.end(), [](const Cube& cube) { return cube.timeTillDeletion <= 0; }), cubes.end());*/\n}\n\nvoid DebugRenderer::renderLines(std::vector<Line>& lines, const f32m4 &vp, const f32m4& w, const f64v3& playerPos, const double deltaT) {\n    std::vector<SimpleMeshVertex> m_vertices(lines.size() * 2);\n    \n    int index = 0;\n    for (auto& l : lines) {\n        m_vertices[index].position = f32v3(l.position1 - playerPos);\n        m_vertices[index].color = l.color;\n        m_vertices[index + 1].position = f32v3(l.position2 - playerPos);\n        m_vertices[index + 1].color = l.color;\n        index += 2;\n        l.timeTillDeletion -= deltaT;\n    }\n\n    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);\n    glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(SimpleMeshVertex), nullptr, GL_DYNAMIC_DRAW);\n    glBufferSubData(GL_ARRAY_BUFFER, 0, m_vertices.size() * sizeof(SimpleMeshVertex), m_vertices.data());\n    \n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    glVertexAttribPointer(m_program.getAttribute(\"vPosition\"), 3, GL_FLOAT, GL_FALSE, sizeof(SimpleMeshVertex), offsetptr(SimpleMeshVertex, position));\n    glVertexAttribPointer(m_program.getAttribute(\"vColor\"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SimpleMeshVertex), offsetptr(SimpleMeshVertex, color));\n    f32m4 mvp = vp * w;\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, GL_FALSE, &mvp[0][0]);\n\n    glDrawArrays(GL_LINES, 0, m_vertices.size());\n\n    lines.erase(std::remove_if(lines.begin(), lines.end(), [](const Line& line) { return line.timeTillDeletion <= 0; }), lines.end());\n}\n\nvoid DebugRenderer::createIcosphere(const int lod) {\n    std::vector<ui32> indices;\n    std::vector<f32v3> positions;\n    vmesh::generateIcosphereMesh(lod, indices, positions);\n  //  m_icosphereMeshes[lod] = createMesh(positions.data(), positions.size(), indices.data(), indices.size());\n}\n\ninline f32v3 findMidpoint(const f32v3& vertex1, const f32v3& vertex2) {\n    return glm::normalize(f32v3((vertex1.x + vertex2.x) / 2.0f, (vertex1.y + vertex2.y) / 2.0f, (vertex1.z + vertex2.z) / 2.0f));\n}\n"
  },
  {
    "path": "SoA/DebugRenderer.h",
    "content": "#pragma once\n#include <chrono>\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/GLProgram.h>\n\nconst static float GOLDEN_RATIO = 1.61803398875f;\n\nconst static int NUM_CUBE_VERTICES = 8;\nconst static f32v3 CUBE_VERTICES[8] = {\n    //front\n    f32v3(-0.5f, -0.5f, 0.5f),\n    f32v3(0.5f, -0.5f, 0.5f),\n    f32v3(0.5f, 0.5f, 0.5f),\n    f32v3(-0.5f, 0.5f, 0.5f),\n    // back\n    f32v3(-0.5f, -0.5f, -0.5f),\n    f32v3(0.5f, -0.5f, -0.5f),\n    f32v3(0.5f, 0.5f, -0.5f),\n    f32v3(-0.5f, 0.5f, -0.5f),\n};\n\nconst static int NUM_CUBE_INDICES = 36;\nconst static GLuint CUBE_INDICES[36] = {\n    // front\n    0, 1, 2,\n    2, 3, 0,\n    // top\n    3, 2, 6,\n    6, 7, 3,\n    // back\n    7, 6, 5,\n    5, 4, 7,\n    // bottom\n    4, 5, 1,\n    1, 0, 4,\n    // left\n    4, 0, 3,\n    3, 7, 4,\n    // right\n    1, 5, 6,\n    6, 2, 1,\n};\n\nstruct SimpleMeshVertex {\n    f32v3 position;\n    color4 color;\n};\n\nstruct SimpleMesh {\n    std::vector<f32v3> vertices;\n    std::vector<ui32> indices;\n};\n\nstruct Icosphere {\n    f64v3 position;\n    float radius;\n    color4 color;\n    int lod;\n    double timeTillDeletion; //ms\n};\n\nstruct Cube {\n    f64v3 position;\n    f64v3 size;\n    color4 color;\n    double timeTillDeletion; //ms\n};\n\nstruct Line {\n    f64v3 position1;\n    f64v3 position2;\n    color4 color;\n    double timeTillDeletion; //ms\n};\n\nstruct DebugRenderContext {\n    std::vector<Icosphere> icospheres;\n    std::vector<Cube> cubes;\n    std::vector<Line> lines;\n};\n\nclass DebugRenderer {\npublic:\n    ~DebugRenderer();\n\n    void render(const f32m4 &vp, const f64v3& viewPosition, const f32m4& w = f32m4(1.0));\n\n    void drawIcosphere(const f64v3 &position, const float radius, const color4 &color, const int lod, ui32 context = 0, const double duration = FLT_MAX);\n    void drawCube(const f64v3 &position, const f64v3 &size, const color4 &color, ui32 context = 0, const double duration = FLT_MAX);\n    void drawLine(const f64v3 &startPoint, const f64v3 &endPoint, const color4 &color, ui32 context = 0, const double duration = FLT_MAX);\n\nprivate:\n    void renderIcospheres(std::vector<Icosphere>& icospheres, const f32m4& vp, const f32m4& w, const f64v3& viewPosition, const double deltaT);\n    void renderCubes(std::vector<Cube>& cubes, const f32m4& vp, const f32m4& w, const f64v3& viewPosition, const double deltaT);\n    void renderLines(std::vector<Line>& lines, const f32m4& v, const f32m4& w, const f64v3& viewPosition, const double deltaT);\n\n    void createIcosphere(const int lod);\n\n    std::map<ui32, DebugRenderContext> m_contexts;\n\n    //Icosphere meshes sorted by level of detail\n    std::map<int, SimpleMesh> m_icosphereMeshes;\n\n    // Program that is currently in use\n    vg::GLProgram m_program;\n\n    VGBuffer m_vbo = 0;\n    VGIndexBuffer m_ibo = 0;\n\n    std::chrono::high_resolution_clock::time_point m_previousTimePoint;\n    std::chrono::high_resolution_clock::time_point m_currentTimePoint;\n};"
  },
  {
    "path": "SoA/Density.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Density.h\"\n#include \"VoxelMatrix.h\"\n\nconst VoxelMatrix* gMatrix;\n\n// ----------------------------------------------------------------------------\n\nfloat Sphere(const f32v3& worldPosition, const f32v3& origin, float radius) {\n    return glm::length(worldPosition - origin) - radius;\n}\n\n// ----------------------------------------------------------------------------\n\nfloat Cuboid(const f32v3& worldPosition, const f32v3& origin, const f32v3& halfDimensions) {\n    const f32v3& local_pos = worldPosition - origin;\n    const f32v3& pos = local_pos;\n\n    const f32v3& d = glm::abs(pos) - halfDimensions;\n    const float m = glm::max(d.x, glm::max(d.y, d.z));\n    return glm::min(m, glm::length(glm::max(d, f32v3(0.f))));\n}\n\n// ----------------------------------------------------------------------------\n\nfloat FractalNoise(\n    const int octaves,\n    const float frequency,\n    const float lacunarity,\n    const float persistence,\n    const f32v2& position) {\n    const float SCALE = 1.f / 128.f;\n    f32v2 p = position * SCALE;\n    float noise = 0.f;\n\n    float amplitude = 1.f;\n    p *= frequency;\n\n    for (int i = 0; i < octaves; i++) {\n    //    noise += simplex(p) * amplitude;\n        p *= lacunarity;\n        amplitude *= persistence;\n    }\n\n    // move into [0, 1] range\n    return 0.5f + (0.5f * noise);\n}\n\n// ----------------------------------------------------------------------------\n\nfloat Density_Func(const f32v3& worldPosition) {\n    i32v3 pos(glm::round(worldPosition));\n    float rv = 0.0f;\n    if (gMatrix->getColorAndCheckBounds(pos + i32v3(gMatrix->size.x / 2, gMatrix->size.y / 2, gMatrix->size.z / 2)).a != 0) {\n        rv += 100.0f;\n    } else {\n        rv -= 100.0f;\n    }\n   // return 20.0f;\n    \n  //  const float MAX_HEIGHT = 20.f;\n  //  const float noise = FractalNoise(4, 0.5343f, 2.2324f, 0.68324f, vec2(worldPosition.x, worldPosition.z));\n  //  const float terrain = worldPosition.y - (MAX_HEIGHT * noise);\n\n  //  const float cube = Cuboid(worldPosition, vec3(-4., 10.f, -4.f), vec3(12.f));\n    const float sphere = Sphere(worldPosition, f32v3(15.f, 2.5f, 1.f), 16.f);\n\n    return sphere + rv;\n}"
  },
  {
    "path": "SoA/Density.h",
    "content": "#ifndef\t\tHAS_DENSITY_H_BEEN_INCLUDED\n#define\t\tHAS_DENSITY_H_BEEN_INCLUDED\n\n#include \"Vorb/types.h\"\n\nclass VoxelMatrix;\n\nextern const VoxelMatrix* gMatrix;\n\nfloat Density_Func(const f32v3& worldPosition);\n\n#endif\t//\tHAS_DENSITY_H_BEEN_INCLUDED"
  },
  {
    "path": "SoA/DevConsole.cpp",
    "content": "#include \"stdafx.h\"\n#include \"DevConsole.h\"\n\nDevConsole DevConsole::m_instance;\n\nvoid DevConsole::init(int maxHistory) {\n    // TODO(Ben): Add setCapacity\n    new (&m_history) CommandRing(maxHistory);\n}\n\nvoid DevConsole::addListener(const nString& command, FuncNewCommand f, void* meta) {\n    EventBinding eb = { f, meta };\n    m_commandListeners[command].emplace_back(eb);\n}\n\n// Adds listener for any command\nvoid DevConsole::addListener(FuncNewCommand f, void* meta) {\n    EventBinding eb = { f, meta };\n    m_anyCommandListeners.emplace_back(eb);\n}\n\nbool DevConsole::removeListener(const nString& command, FuncNewCommand f) {\n    auto it = m_commandListeners.find(command);\n    if (it == m_commandListeners.end()) return false;\n    auto& listeners = it->second;\n    auto foundListener = std::find(listeners.begin(), listeners.end(), f);\n    if (foundListener != listeners.end()) {\n        listeners.erase(foundListener, foundListener + 1);\n        return true;\n    }\n    return false;\n}\n\nbool DevConsole::removeListener(FuncNewCommand f) {\n    auto foundListener = std::find(m_anyCommandListeners.begin(), m_anyCommandListeners.end(), f);\n    if (foundListener != m_anyCommandListeners.end()) {\n        m_anyCommandListeners.erase(foundListener, foundListener + 1);\n        return true;\n    }\n    return false;\n}\n\nvoid DevConsole::addCommand(const nString& s) {\n    m_commandListeners.emplace(s, std::vector<EventBinding>());\n}\n\nbool DevConsole::write(nString s) {\n    \n    // Remove leading `\n    while (s.size() && s.front() == '`') {\n        s.erase(0, 1);\n    }\n    if (s.empty()) return false;\n    // TODO(Ben): Concern about thread safety.\n    // Ringbuffer push invalidates data... have to copy\n    nString sCopy = s;\n    m_history.push(sCopy);\n    // Broadcast to listeners listening for any event\n    for (auto& eb : m_anyCommandListeners) {\n        eb.function(eb.metaData, s);\n    }\n    // Broadcast to specific listeners.\n    nString command = getFirstToken(s);\n    auto it = m_commandListeners.find(command);\n    if (it == m_commandListeners.end()) return false;\n    for (auto& eb : it->second) {\n        eb.function(eb.metaData, s);\n    }\n    return true;\n}\n\nvoid DevConsole::toggleFocus() {\n    m_isFocused = !m_isFocused;\n    if (m_isFocused) {\n        // Enable input\n        vui::InputDispatcher::key.onKeyDown += makeDelegate(this, &DevConsole::onKeyDown);\n        vui::InputDispatcher::key.onText += makeDelegate(this, &DevConsole::onTextInput);\n    } else {\n        // Disable input\n        vui::InputDispatcher::key.onKeyDown -= makeDelegate(this, &DevConsole::onKeyDown);\n        vui::InputDispatcher::key.onText -= makeDelegate(this, &DevConsole::onTextInput);\n    }\n}\n\nvoid DevConsole::setFocus(bool focus) {\n    if (focus != m_isFocused) {\n        toggleFocus();  \n    }\n}\n\nconst nString& DevConsole::getHistory(const i32& index) {\n    return m_history.at(index);\n}\n\nnString DevConsole::getFirstToken(nString input) {\n    size_t i = 0;\n    while (i < input.size()) {\n        while (input[i] == ' ') i++;\n        size_t start = i;\n        while (input[i] != ' ' && i < input.size()) i++;\n        if (i - start > 0) {\n            return input.substr(start, i - start);\n        }\n    }\n    return \"\";\n}\n\nvoid DevConsole::tokenize(nString& input, OUT std::vector<nString>& tokens) {\n    // TODO(Ben): Pass in delimiters\n    size_t i = 0;\n    while (i < input.size()) {\n        while (input[i] == ' ') i++;\n        size_t start = i;\n        while (input[i] != ' ' && i < input.size()) i++;\n        if (i - start > 0) {\n            tokens.emplace_back(input.substr(i, i - start));\n        }\n    }\n}\n\nvoid DevConsole::onKeyDown(Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& ev) {\n    // TODO(Ben): Unicode is gonna be a nightmare\n    if (ev.keyCode == VKEY_RETURN || ev.keyCode == VKEY_RETURN2) {\n        write(m_currentLine);\n        m_currentLine = \"\";\n    } else if (ev.keyCode == VKEY_BACKSPACE || ev.keyCode == VKEY_DELETE) {\n        if (m_currentLine.size()) m_currentLine.pop_back();\n    }\n}\n\nvoid DevConsole::onTextInput(Sender s VORB_MAYBE_UNUSED, const vui::TextEvent& ev) {\n    const char* t = ev.text;\n    while (*t != '\\0') {\n        m_currentLine += (*t);\n        t++;\n    }\n}"
  },
  {
    "path": "SoA/DevConsole.h",
    "content": "#pragma once\n#include <Vorb/RingBuffer.hpp>\n#include <Vorb/ui/InputDispatcher.h>\n\ntypedef vorb::ring_buffer<nString> CommandRing;\ntypedef void(*FuncNewCommand)(void* metadata, const nString& command);\n\nclass DevConsole {\npublic:\n    DevConsole() : m_history(50) {};\n    static DevConsole& getInstance() { return m_instance; }\n\n    void init(int maxHistory);\n\n    // Adds listener for a specific command\n    void addListener(const nString& command, FuncNewCommand f, void* meta);\n    // Adds listener for any command\n    void addListener(FuncNewCommand f, void* meta);\n    // Removes listener for specific command\n    bool removeListener(const nString& command, FuncNewCommand f);\n    // Removes listener for any command\n    bool removeListener(FuncNewCommand f);\n\n    void addCommand(const nString& s);\n    bool write(nString s);\n\n    void toggleFocus();\n    void setFocus(bool focus);\n    const bool& isFocused() { return m_isFocused; }\n\n    const nString& getHistory(const i32& index);\n    const nString& getCurrentLine() { return m_currentLine; }\n\n    // Utilities for tokenizing strings\n    static nString getFirstToken(nString input);\n    static void tokenize(nString& input, OUT std::vector<nString>& tokens);\nprivate:\n    class EventBinding {\n    public:\n        FuncNewCommand function;\n        void* metaData;\n\n        bool operator== (const FuncNewCommand& f) {\n            return function == f;\n        }\n    };\n\n    void onKeyDown(Sender s, const vui::KeyEvent& ev);\n    void onTextInput(Sender s, const vui::TextEvent& ev);\n\n    bool m_isFocused = false;\n    nString m_currentLine = \"\";\n    CommandRing m_history;\n    std::unordered_map<nString, std::vector<EventBinding>> m_commandListeners; ///< For specific commands only\n    std::vector<EventBinding> m_anyCommandListeners;\n\n    static DevConsole m_instance; ///< Singleton\n};\n"
  },
  {
    "path": "SoA/DevConsoleView.cpp",
    "content": "#include \"stdafx.h\"\n#include \"DevConsoleView.h\"\n#include \"textureUtils.h\"\n\n#include <algorithm>\n#include <iterator>\n\n#include <Vorb/graphics/GLStates.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n\n#include \"DevConsole.h\"\n\nDevConsoleView::DevConsoleView() :\n    m_renderRing(START_LINES_TO_RENDER) {\n}\n\nDevConsoleView::~DevConsoleView() {\n    dispose();\n}\n\nvoid DevConsoleView::init(DevConsole* console, i32 linesToRender, const f32v2& position, float lineWidth) {\n    \n    m_batch = new vg::SpriteBatch();\n    m_batch->init();\n    m_font = new vg::SpriteFont();\n    m_font->init(\"Fonts/orbitron_black-webfont.ttf\", 32);\n    \n    m_position = position;\n    m_dimensions.x = lineWidth;\n    m_dimensions.y = linesToRender * m_font->getFontHeight() + 40.0f;\n    m_linesToRender = linesToRender;\n\n    m_renderRing.resize(linesToRender);\n    m_renderRing.clear();\n\n    m_console = console;\n    _fHook = [](void* meta, const nString& str) {\n        ((DevConsoleView*)meta)->onNewCommand(str);\n    };\n    m_console->addListener(_fHook, this);\n    m_isViewModified = true;\n\n    \n\n    initSinglePixelTexture(m_texture, color::White);\n}\n\nvoid DevConsoleView::dispose() {\n    if (m_batch) {\n        m_batch->dispose();\n        m_batch = nullptr;\n    }\n    if (m_font) {\n        m_font->dispose();\n        m_font = nullptr;\n    }\n    if (m_console) {\n        if (_fHook) {\n            m_console->removeListener(_fHook);\n            _fHook = nullptr;\n        }\n        m_console = nullptr;\n    }\n}\n\nvoid DevConsoleView::update(const f32& dt) {\n    // Blinking Logic\n    m_blinkTimeRemaining -= dt;\n    if (m_blinkTimeRemaining < 0) {\n        m_blinkTimeRemaining = DEV_CONSOLE_MARKER_BLINK_DELAY;\n        m_isViewModified = true;\n    }\n\n    if (m_currentLine != m_console->getCurrentLine()) {\n        m_currentLine = m_console->getCurrentLine();\n        m_isViewModified = true;\n    }\n\n    if (m_isViewModified) redrawBatch();\n}\n\nvoid DevConsoleView::render(const f32v2& screenSize) {\n    // Check For A Batch\n    if (!m_batch) return;\n\n    redrawBatch(); // TODO(Ben): Not every frame\n    m_batch->render(screenSize, &vg::SamplerState::POINT_WRAP, &vg::DepthState::NONE, &vg::RasterizerState::CULL_NONE);\n}\n\nvoid DevConsoleView::setBackColor(const color4& color) {\n    m_backColor = color;\n    m_isViewModified = true;\n}\n\nvoid DevConsoleView::setFontColor(const color4& color) {\n    m_fontColor = color;\n    m_isViewModified = true;\n}\n\nvoid DevConsoleView::setPosition(const f32v2& pos) {\n    m_position = pos;\n    m_isViewModified = true;\n}\n\nvoid DevConsoleView::setDimensions(const f32v2& dims) {\n    m_dimensions = dims;\n    m_isViewModified = true;\n}\n\nvoid DevConsoleView::onNewCommand(const nString& str) {\n    std::stringstream ss(str);\n    std::string item;\n    while (std::getline(ss, item, '\\n')) {\n        if (!m_renderRing.push(item)) {\n            m_renderRing.pop();\n            m_renderRing.push(item);\n        }\n    }\n\n    m_isViewModified = true;\n}\n\nvoid DevConsoleView::redrawBatch() {\n    if (!m_batch || !m_font) return;\n\n    m_batch->begin();\n    f32 textHeight = (f32)m_font->getFontHeight();\n\n    f32 yOffset = m_renderRing.size() * textHeight;\n\n    // Draw dark transparent back\n    m_batch->draw(m_texture, m_position - f32v2(10.0f, m_dimensions.y - textHeight - 10.0f), m_dimensions, color4(0, 0, 0, 176), 1.0f);\n\n    // Draw Command Lines\n    size_t i;\n    for (i = 0; i < m_renderRing.size(); i++) {\n        const cString cStr = m_renderRing.at(i).c_str();\n        if (cStr) {\n            m_batch->drawString(m_font, cStr,\n                m_position + f32v2(0.0f, textHeight * i + 10.0f - yOffset),\n                f32v2(1),\n                color4(0, 255, 0, 255),\n                vg::TextAlign::TOP_LEFT,\n                0.9f);\n        }\n    }\n    // Draw current line\n    if (m_currentLine.size()) {\n        m_batch->drawString(m_font, m_currentLine.c_str(),\n                            m_position + f32v2(0.0f, textHeight * i + 10.0f - yOffset),\n                            f32v2(1),\n                            color4(0, 255, 0, 255),\n                            vg::TextAlign::TOP_LEFT,\n                            0.9f);\n    }\n\n    // TODO: Draw Input\n    m_batch->end(vg::SpriteSortMode::BACK_TO_FRONT);\n}\n"
  },
  {
    "path": "SoA/DevConsoleView.h",
    "content": "#pragma once\n\n#include <SDL2/SDL.h>\n#include <Vorb/RingBuffer.hpp>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/colors.h>\n#include <Vorb/graphics/gtypes.h>\n\nclass DevConsole;\n\nDECL_VG(class SpriteBatch;\n        class SpriteFont)\n\ntypedef vorb::ring_buffer<nString> StringRing;\n\nconst f32 DEV_CONSOLE_MARKER_BLINK_DELAY = 0.85f;\nconst int START_LINES_TO_RENDER = 2;\n\nclass DevConsoleView {\npublic:\n    DevConsoleView();\n    ~DevConsoleView();\n\n    // Position is of bottom left corner\n    void init(DevConsole* console, i32 linesToRender, const f32v2& position, float lineWidth);\n   \n\n    void dispose();\n\n    void update(const f32& dt);\n\n    void render(const f32v2& screenSize);\n\n    /************************************************************************/\n    /* Setters                                                              */\n    /************************************************************************/\n    void setBackColor(const color4& color);\n    void setFontColor(const color4& color);\n    void setPosition(const f32v2& pos);\n    void setDimensions(const f32v2& dims);\n\n    /************************************************************************/\n    /* Getters                                                              */\n    /************************************************************************/\n    const color4& getBackColor() const { return m_backColor; }\n    const color4& getFontColor() const { return m_fontColor; }\n    const f32v2& getPosition() const { return m_position; }\n    const f32v2& getDimensions() const { return m_dimensions; }\nprivate:\n    void onNewCommand(const nString& str);\n    void redrawBatch();\n\n    DevConsole* m_console = nullptr;\n    void(*_fHook) (void*, const nString&);\n\n    vg::SpriteBatch* m_batch = nullptr;\n    vg::SpriteFont* m_font = nullptr;\n    bool m_isViewModified = false;\n    nString m_currentLine = \"\";\n\n    f32v2 m_position = f32v2(0.0f);\n    f32v2 m_dimensions = f32v2(0.0f);\n    color4 m_backColor = color4(0, 0, 0, 128);\n    color4 m_fontColor = color::LightGreen;\n\n    VGTexture m_texture;\n\n    i32 m_linesToRender = START_LINES_TO_RENDER;\n    StringRing m_renderRing;\n    f32 m_blinkTimeRemaining = DEV_CONSOLE_MARKER_BLINK_DELAY;\n};\n"
  },
  {
    "path": "SoA/DevHudRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"DevHudRenderStage.h\"\n\n#include <Vorb/colors.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n\n#include \"App.h\"\n\nDevHudRenderStage::DevHudRenderStage() {\n    // Empty\n}\n\nDevHudRenderStage::~DevHudRenderStage() {\n    delete _spriteBatch;\n    delete _spriteFont;\n}\n\nvoid DevHudRenderStage::hook(const cString fontPath, i32 fontSize,\n          const App* app, const f32v2& windowDims) {\n    _spriteBatch = new vg::SpriteBatch(true, true);\n    _spriteFont = new vg::SpriteFont();\n    _app = app;\n    _windowDims = windowDims;\n    _spriteFont->init(fontPath, fontSize);\n    _fontHeight = _spriteFont->getFontHeight();\n}\n\nvoid DevHudRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    // Reset the yOffset\n    _yOffset = 0;\n\n    _spriteBatch->begin();\n\n    // Draw crosshair\n    if (_mode >= DevUiModes::CROSSHAIR) {\n        drawCrosshair();\n    }\n\n    // Fps Counters\n    if (_mode >= DevUiModes::FPS) {\n        drawFps();\n    }\n\n    // Items in hands\n    if (_mode >= DevUiModes::HANDS) {\n        drawHands();\n    }\n\n    // Positional text\n    if (_mode >= DevUiModes::POSITION) {\n        drawPosition();\n    }\n\n    _spriteBatch->end();\n    // Render to the screen\n    _spriteBatch->render(_windowDims);\n}\n\nvoid DevHudRenderStage::cycleMode(int offset /*= 1*/) {\n    \n    // The last element in DevUiModes\n    const int last = static_cast<int>(DevUiModes::LAST);\n    // Treat it as an int when cycling so we can do integer math\n    int imode = static_cast<int>(_mode) + offset;\n    if (imode < 0) {\n        // Negative wrap\n        imode = last - ((abs(imode) - 1) % (last + 1));\n    } else {\n        // Positive wrap\n        imode = imode % (last + 1);\n    }\n    // Cast it back to a DevUiMode\n    _mode = static_cast<DevUiModes>(imode);\n}\n\nvoid DevHudRenderStage::drawCrosshair() {\n    // const f32v2 cSize(26.0f);\n //   _spriteBatch->draw(crosshairTexture.id,\n //                      (_windowDims - cSize) / 2.0f,\n //                      cSize,\n //                      ColorRGBA8(255, 255, 255, 128));\n}\n\nvoid DevHudRenderStage::drawHands() {\n   // const f32v2 SCALE(0.75f);\n   // char buffer[256];\n    // Left Hand\n    //if (_player->leftEquippedItem) {\n    //    std::sprintf(buffer, \"Left Hand: %s (%d)\",\n    //                 _player->leftEquippedItem->name.c_str(),\n    //                 _player->leftEquippedItem->count);\n\n    //    _spriteBatch->drawString(_spriteFont,\n    //                             buffer,\n    //                             f32v2(0.0f, _windowDims.y - _fontHeight),\n    //                             SCALE,\n    //                             color::White);\n    //}\n    //// Right Hand\n    //if (_player->rightEquippedItem) {\n    //    std::sprintf(buffer, \"Right Hand: %s (%d)\",\n    //                 _player->rightEquippedItem->name.c_str(),\n    //                 _player->rightEquippedItem->count);\n\n    //    _spriteBatch->drawString(_spriteFont,\n    //                             buffer,\n    //                             f32v2(_windowDims.x - _spriteFont->measure(buffer).x, _windowDims.y - _fontHeight),\n    //                             SCALE,\n    //                             color::White);\n    //}\n}\n\nvoid DevHudRenderStage::drawFps() {\n    char buffer[256];\n    std::sprintf(buffer, \"Render FPS: %.0f\", _app->getFps());\n    _spriteBatch->drawString(_spriteFont,\n                             buffer,\n                             f32v2(0.0f, _yOffset),\n                             f32v2(1.0f),\n                             color::White);\n    _yOffset += _fontHeight;\n\n   /* std::sprintf(buffer, \"Physics FPS: %.0f\", physicsFps);\n    _spriteBatch->drawString(_spriteFont,\n                             buffer,\n                             f32v2(0.0f, _yOffset),\n                             f32v2(1.0f),\n                             color::White);\n    _yOffset += _fontHeight;*/\n}\n\nvoid DevHudRenderStage::drawPosition() {\n    // const f32v2 NUMBER_SCALE(0.75f);\n   // char buffer[256];\n    // Grid position\n    _yOffset += _fontHeight;\n\n    _spriteBatch->drawString(_spriteFont,\n                             \"Grid Position\",\n                             f32v2(0.0f, _yOffset),\n                             f32v2(1.0f),\n                             color::White);\n    _yOffset += _fontHeight;\n\n   /* std::sprintf(buffer, \"X %.2f\", _player->headPosition.x);\n    _spriteBatch->drawString(_spriteFont,\n                             buffer,\n                             f32v2(0.0f, _yOffset),\n                             NUMBER_SCALE,\n                             color::White);\n    _yOffset += _fontHeight;\n\n    std::sprintf(buffer, \"Y %.2f\", _player->headPosition.y);\n    _spriteBatch->drawString(_spriteFont,\n                             buffer,\n                             f32v2(0.0f, _yOffset),\n                             NUMBER_SCALE,\n                             color::White);\n    _yOffset += _fontHeight;\n\n    std::sprintf(buffer, \"Z %.2f\", _player->headPosition.z);\n    _spriteBatch->drawString(_spriteFont,\n                             buffer,\n                             f32v2(0.0f, _yOffset),\n                             NUMBER_SCALE,\n                             color::White);\n    _yOffset += _fontHeight;*/\n\n    // World position\n    _yOffset += _fontHeight;\n    _spriteBatch->drawString(_spriteFont,\n                             \"World Position\",\n                             f32v2(0.0f, _yOffset),\n                             f32v2(1.0f),\n                             color::White);\n    _yOffset += _fontHeight;\n\n  /*  std::sprintf(buffer, \"X %-9.2f\", _player->worldPosition.x);\n    _spriteBatch->drawString(_spriteFont,\n                             buffer,\n                             f32v2(0.0f, _yOffset),\n                             NUMBER_SCALE,\n                             color::White);\n    _yOffset += _fontHeight;\n\n    std::sprintf(buffer, \"Y %-9.2f\", _player->worldPosition.y);\n    _spriteBatch->drawString(_spriteFont,\n                             buffer,\n                             f32v2(0.0f, _yOffset),\n                             NUMBER_SCALE,\n                             color::White);\n    _yOffset += _fontHeight;\n\n    std::sprintf(buffer, \"Z %-9.2f\", _player->worldPosition.z);\n    _spriteBatch->drawString(_spriteFont,\n                             buffer,\n                             f32v2(0.0f, _yOffset),\n                             NUMBER_SCALE,\n                             color::White);\n    _yOffset += _fontHeight;*/\n}\n"
  },
  {
    "path": "SoA/DevHudRenderStage.h",
    "content": "/// \n///  DevHudRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 2 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file provides the render stage for\n///  drawing the dev/debug Hud.\n///\n\n#pragma once\n\n#ifndef DevHudRenderStage_h__\n#define DevHudRenderStage_h__\n\n#include \"IRenderStage.h\"\n#include <Vorb/VorbPreDecl.inl>\n\nDECL_VG(class SpriteBatch;\n        class SpriteFont)\n\nclass App;\n\nclass DevHudRenderStage : public IRenderStage{\npublic:\n    DevHudRenderStage();\n    ~DevHudRenderStage();\n\n    void hook(const cString fontPath, i32 fontSize,\n              const App* app, const f32v2& windowDims);\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera) override;\n\n    /// Cycles the Hud mode\n    /// @param offset: How much to offset the current mode\n    void cycleMode(int offset = 1);\n\n    // Each mode includes the previous mode\n    enum class DevUiModes {\n        NONE = 0,\n        CROSSHAIR = 1,\n        HANDS = 2,\n        FPS = 3,\n        POSITION = 4,\n        LAST = POSITION // Make sure LAST is always last\n    };\n\nprivate:\n    void drawCrosshair();\n    void drawHands();\n    void drawFps();\n    void drawPosition();\n\n    vg::SpriteBatch* _spriteBatch = nullptr; ///< For rendering 2D sprites\n    vg::SpriteFont* _spriteFont = nullptr; ///< Font used by spritebatch\n    DevUiModes _mode = DevUiModes::HANDS; ///< The mode for rendering\n    f32v2 _windowDims; ///< Dimensions of the window\n    const App* _app = nullptr; ///< Handle to the app\n    int _fontHeight; ///< Height of the spriteFont\n    int _yOffset; ///< Y offset accumulator\n};\n\n#endif // DevHudRenderStage_h__"
  },
  {
    "path": "SoA/DevScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"DevScreen.h\"\n\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/colors.h>\n#include <Vorb/ui/KeyStrings.h>\n\n#define DEV_SCREEN_FONT \"Fonts/orbitron_bold-webfont.ttf\"\n#define DEV_SCREEN_FONT_SIZE 32\n\nconst cString TITLE = \"Dev Screen\";\nconst color4& FONT_COLOR = color::AliceBlue;\n\ni32 DevScreen::getNextScreen() const {\n    if (m_nextScreen) return m_nextScreen->getIndex();\n    return SCREEN_INDEX_NO_SCREEN;\n}\ni32 DevScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid DevScreen::build() {\n    // Empty\n}\nvoid DevScreen::destroy(const vui::GameTime&) {\n    // Empty\n}\n\nvoid DevScreen::onEntry(const vui::GameTime&) {\n    m_delegatePool.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&] (Sender, const vui::KeyEvent& e) {\n        auto kvp = m_screenMapping.find((VirtualKey)e.keyCode);\n        if (kvp == m_screenMapping.end()) return;\n        m_nextScreen = kvp->second;\n    });\n\n    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);\n    glClearDepth(1.0);\n\n    m_nextScreen = nullptr;\n    deferCounter = 1;\n\n    m_sb = new vg::SpriteBatch(true, true);\n    m_font = new vg::SpriteFont();\n    m_font->init(DEV_SCREEN_FONT, DEV_SCREEN_FONT_SIZE);\n}\nvoid DevScreen::onExit(const vui::GameTime&) {\n    m_delegatePool.dispose();\n    m_sb->dispose();\n    delete m_sb;\n    m_sb = nullptr;\n\n    m_font->dispose();\n    delete m_font;\n    m_font = nullptr;\n}\n\nvoid DevScreen::update(const vui::GameTime&) {\n    if (m_nextScreen) {\n        if (deferCounter) {\n            --deferCounter;\n        } else {\n            m_state = vui::ScreenState::CHANGE_NEXT;\n        }\n    }\n}\n\nvoid DevScreen::draw(const vui::GameTime&) {\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    const vui::GameWindow* w = &m_game->getWindow();\n\n    m_sb->begin();\n\n    f32v2 pos(90.0f, 300.0f);\n    f32 posInc = 35.0f;\n\n    if (m_nextScreen) {\n        // Draw loading message\n        m_sb->drawString(m_font, \"Loading... please wait.\", f32v2(w->getWidth() * 0.5f, w->getHeight() * 0.5f), f32v2(1.0f), FONT_COLOR, vg::TextAlign::CENTER);\n    } else {\n        // Draw title\n        m_sb->drawString(m_font, TITLE, f32v2((w->getWidth() - m_font->measure(TITLE).x * 1.5) / 2.0, 50.0f),\n                         f32v2(1.5f), FONT_COLOR);\n        // Draw strings\n        m_sb->drawString(m_font, \"* Press one of the following keys to enter a screen:\", pos, f32v2(1.0f), FONT_COLOR);\n   \n        pos.y += posInc * 2.0f;\n        for (auto& it : m_screenMapping) {\n            m_sb->drawString(m_font, m_screenNames[it.first].c_str(), pos, f32v2(1.0f), FONT_COLOR);\n            pos.y += posInc;\n        }\n    }\n    m_sb->end();\n    m_sb->render(f32v2(w->getWidth(), w->getHeight()));\n}\n\nvoid DevScreen::addScreen(VirtualKey vKey, vui::IGameScreen* s, const nString& name) {\n    m_screenMapping[vKey] = s;\n    m_screenNames[vKey] = nString(VirtualKeyStrings[vKey]) + \": \" + name;\n}\n"
  },
  {
    "path": "SoA/DevScreen.h",
    "content": "///\n/// DevScreen.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 14 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Allows developers to bypass normal startup into other screens\n///\n\n#pragma once\n\n#ifndef DevScreen_h__\n#define DevScreen_h__\n\n#include <Vorb/Event.hpp>\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/ui/KeyboardEventDispatcher.h>\n#include <Vorb/VorbPreDecl.inl>\n\nDECL_VG(class SpriteBatch; class SpriteFont)\n\nclass DevScreen : public vui::IGameScreen {\npublic:\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\n\n    /// Registers a screen that developers can access\n    /// @param vKey: Key code used to access the screen\n    /// @param s: Screen\n    /// @param name: Display name\n    void addScreen(VirtualKey vKey, vui::IGameScreen* s, const nString& name);\nprivate:\n    std::map<VirtualKey, vui::IGameScreen*> m_screenMapping; ///< Stores available screen targets\n    std::map<VirtualKey, nString> m_screenNames; ///< Stores display names of screens\n    AutoDelegatePool m_delegatePool; ///< Input hooks reservoir\n    vui::IGameScreen* m_nextScreen = nullptr; ///< The next screen\n    int deferCounter = 1; //< When this hits 0 we change screen\n    vg::SpriteBatch* m_sb = nullptr;\n    vg::SpriteFont* m_font = nullptr;\n};\n\n#endif // DevScreen_h__"
  },
  {
    "path": "SoA/Doxyfile.in",
    "content": "PROJECT_NAME           = \"@CMAKE_PROJECT_NAME@\"\nPROJECT_NUMBER         = @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@\nSTRIP_FROM_PATH        = @PROJECT_SOURCE_DIR@ \\\n                         @PROJECT_BINARY_DIR@\nINPUT                  = @doxy_main_page@ \\\n                         @PROJECT_SOURCE_DIR@ \\\n                         @PROJECT_BINARY_DIR@\nFILE_PATTERNS          = *.h \\\n                         *.cc\nRECURSIVE              = YES\nUSE_MDFILE_AS_MAINPAGE = @doxy_main_page@"
  },
  {
    "path": "SoA/DualContouringMesher.cpp",
    "content": "#include \"stdafx.h\"\n#include \"DualContouringMesher.h\"\n#include \"VoxelMatrix.h\"\n#include \"Density.h\"\n\n#include <Vorb/Timing.h>\n\n#include \"Octree.h\"\n\nvoid DualContouringMesher::genMatrixMesh(const VoxelMatrix& matrix, std::vector<VoxelModelVertex>& vertices, std::vector<ui32>& indices) {\n    int octreeSize = glm::max(glm::max(matrix.size.x, matrix.size.y), matrix.size.z);\n\n    gMatrix = &matrix;\n    octreeSize = 128;\n    std::cout << octreeSize << std::endl;\n    const int MAX_THRESHOLDS = 5;\n    const float THRESHOLDS[MAX_THRESHOLDS] = { -1.f, 0.1f, 1.f, 10.f, 50.f };\n    int thresholdIndex = 3;\n    PreciseTimer timer;\n    OctreeNode* root = BuildOctree(i32v3(-octreeSize / 2), octreeSize, THRESHOLDS[thresholdIndex]);\n    std::cout << timer.stop() << std::endl;\n    timer.start();\n    GenerateMeshFromOctree(root, vertices, indices);\n    std::cout << timer.stop() << std::endl;\n}"
  },
  {
    "path": "SoA/DualContouringMesher.h",
    "content": "///\n/// DualContouringMesher.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 15 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// \n///\n\n#pragma once\n\n#ifndef DualContouringMesher_h__\n#define DualContouringMesher_h__\n\n#include \"Octree.h\"\n#include \"VoxelModelMesh.h\"\n\nclass VoxelMatrix;\n\n// TODO(Ben): I don't understand this\n// Source: http://ngildea.blogspot.com/2014/11/implementing-dual-contouring.html\nclass DualContouringMesher {\npublic:\n    static void genMatrixMesh(const VoxelMatrix& matrix, std::vector<VoxelModelVertex>& vertices, std::vector<ui32>& indices);\nprivate:\n\n};\n\n#endif // DualContouringMesher_h__"
  },
  {
    "path": "SoA/ECS Specs.txt",
    "content": "Usage:\n - Systems Are All Loaded Into Main Table\n - Systems Are Initialized In Three Passes\n    * Calls init(i32 pass)\n - Systems Are Updated Every Frame\n    * Calls update(i32 frame, const GameTime& time)\n - Systems May Be Ordered To Load/Save Internal State\n    * Calls i32 getInternalStateSize(), save(ubyte* output), load(ubyte* data)\n\nX==========X\n|Components|\nX==========X\n\nPosition\n - f64v3 Absolute Position\n - f64v3 Position In Local Voxel World\nPhysics\n - f32 Mass\n - f32v3 Acceleration\n - f32v3 Velocity\n - std::vector<f32v3> Impulse List\nCollision\n - \"Collision Skin\"\n\nX=======X\n|Systems|\nX=======X\n\n? Gravity ?\n - Requires \"Physics\" Component\n - Adds Gravitational Force To Acceleration\nPhysics\n - Requires \"Position\" Component\n - Applies Impulses To Positions\n - Simulates Positions As If They Were Point Bodies\n - Clears Acceleration\nCollision\n - Requires \"Position\" Component\n - Takes Collision Skins And Collides Them Against\n   Each Other And The Terrain, Modifying The Position"
  },
  {
    "path": "SoA/ECSTemplates.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ECSTemplates.h\"\n\n#include <Vorb/io/IOManager.h>\n#include <Vorb/io/Keg.h>\n\nvecs::EntityID ECSTemplate::create(vecs::ECS& ecs) {\n    // Create entity.\n    auto e = ecs.addEntity();\n\n    // Add all components.\n    for(auto& kvp : m_components) kvp.second->m_cID = ecs.addComponent(kvp.first, e);\n\n    // Build all components.\n    for(auto& kvp : m_components) kvp.second->build(ecs, e);\n\n    // Run post-build for dependencies and such.\n    for (auto& kvp : m_components) kvp.second->postBuild(ecs, e);\n\n    return e;\n}\n\nvoid ECSTemplateLibrary::loadTemplate(const vpath& file) {\n    ECSTemplate* t = new ECSTemplate();\n\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    { // Parse YAML file\n        vio::IOManager iom;\n        const cString s = iom.readFileToString(file);\n        context.reader.init(s);\n        delete[] s;\n    }\n\n    {\n        vfile f;\n        file.asFile(&f);\n        nString fileName = file.getLeaf();\n        nString templateName = fileName.substr(0, fileName.length() - 4);\n        m_templates[templateName] = t;\n    }\n\n    auto node = context.reader.getFirst();\n    auto f = makeFunctor([&](Sender s VORB_MAYBE_UNUSED, const nString& component, keg::Node node) {\n        auto bb = m_builders.find(component);\n        if(bb != m_builders.end()) {\n            ECSComponentBuilder* builder = bb->second();\n            builder->load(context, node);\n            t->m_components[component] = builder;\n        }\n        context.reader.free(node);\n    });\n    context.reader.forAllInMap(node, &f);\n\n    context.reader.dispose();\n}\n\nvecs::EntityID ECSTemplateLibrary::build(vecs::ECS& ecs, const nString& name) const {\n    auto tmpl = m_templates.find(name);\n    if(tmpl == m_templates.end()) return ID_GENERATOR_NULL_ID;\n    return tmpl->second->create(ecs);\n}\n\nECSTemplateLibrary::~ECSTemplateLibrary() {\n    for(auto& kvp : m_templates) {\n        delete kvp.second;\n    }\n}\n\n"
  },
  {
    "path": "SoA/ECSTemplates.h",
    "content": "//\n// ECSTemplates.h\n//\n// Created by Cristian Zaloj on 16 Mar 2015\n//\n\n#pragma once\n\n#ifndef ECSTemplates_h__\n#define ECSTemplates_h__\n\n#include <Vorb/Event.hpp>\n#include <Vorb/IO.h>\n#include <Vorb/io/Keg.h>\n#include <Vorb/ecs/ECS.h>\n\nclass ECSTemplate;\nclass ECSTemplateLibrary;\n\nclass ECSComponentBuilder {\n    friend class ECSTemplate;\npublic:\n    virtual ~ECSComponentBuilder() {\n        // Empty\n    }\n\n    virtual void load(keg::ReadContext& reader, keg::Node node) = 0;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) = 0;\n    virtual void postBuild(vecs::ECS& ecs VORB_UNUSED, vecs::EntityID eID VORB_UNUSED) { /* Empty */ };\nprotected:\n    vecs::ComponentID m_cID; ///< ID of generated component\n};\n\nclass ECSTemplate {\n    friend class ECSTemplateLibrary;\npublic:\n    virtual ~ECSTemplate() {\n        for(auto& kvp : m_components) delete kvp.second;\n    }\n\n    vecs::EntityID create(vecs::ECS& ecs);\nprivate:\n    std::unordered_map<nString, ECSComponentBuilder*> m_components;\n};\n\nclass ECSTemplateLibrary {\n    typedef Delegate<ECSComponentBuilder*> ComponentBuildFunctionFactory;\npublic:\n    virtual ~ECSTemplateLibrary();\n\n    vecs::EntityID build(vecs::ECS& ecs, const nString& name) const;\n\n    void loadTemplate(const vpath& file);\n\n    template<typename T>\n    void registerFactory(const nString& component) {\n        auto func=[]() -> ECSComponentBuilder* {\n            return new T();\n        };\n\n        m_builders[component] = makeDelegate(&func);\n    }\n\n    template<typename F>\n    void forEachTemplate(F f) {\n        for(auto& kvp : m_templates) f(kvp.first);\n    }\nprivate:\n    std::unordered_map<nString, ECSTemplate*> m_templates;\n    std::unordered_map<nString, ComponentBuildFunctionFactory> m_builders;\n};\n\n#endif // !ECSTemplates_h__\n"
  },
  {
    "path": "SoA/Errors.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Errors.h\"\n\n#include <SDL2/SDL.h>\n\n#ifndef VORB_OS_WINDOWS\n#include <limits.h>\n#include <stdlib.h>\n#endif//VORB_OS_WINDOWS\n\nvoid showMessage(const nString& message VORB_MAYBE_UNUSED)\n{\n#if defined(_WIN32) || defined(_WIN64)\n    //SDL_WM_IconifyWindow();\n    SDL_Delay(100);\n    SDL_SetRelativeMouseMode(SDL_FALSE);\n    MessageBox(NULL, message.c_str(), \"SoA\", MB_OK);\n#else\n    std::cout << \"ERROR! MESSAGE BOX NOT IMPLEMENTED FOR THIS FILE SYSTEM\\n\";\n    int a;\n    std::cin >> a;\n#endif\n}\n\n//yes 1, no 0\nint showYesNoBox(const nString& message VORB_MAYBE_UNUSED)\n{\n#if defined(_WIN32) || defined(_WIN64)\n    SDL_Delay(100);\n    SDL_SetRelativeMouseMode(SDL_FALSE);\n    int id = MessageBox(NULL, message.c_str(), \"SoA\", MB_YESNO);\n    if (id == IDYES) return 1;\n    if (id == IDNO) return 0;\n    return 0;\n#else\n    std::cout << \"ERROR! YESNO BOX NOT IMPLEMENTED FOR THIS FILE SYSTEM\\n\";\n    int a;\n    std::cin >> a;\n    return 0;\n#endif\n}\n\n///yes 1, no 0, cancel -1\nint showYesNoCancelBox(const nString& message VORB_MAYBE_UNUSED)\n{\n#if defined(_WIN32) || defined(_WIN64)\n    SDL_Delay(100);\n    SDL_SetRelativeMouseMode(SDL_FALSE);\n    int id = MessageBox(NULL, message.c_str(), \"SoA\", MB_YESNOCANCEL);\n    if (id == IDYES) return 1;\n    if (id == IDNO) return 0;\n    if (id == IDCANCEL) return -1;\n    return 0;\n#else\n    std::cout << \"ERROR! YESNO BOX NOT IMPLEMENTED FOR THIS FILE SYSTEM\\n\";\n    int a;\n    std::cin >> a;\n    return 0;\n#endif\n}\n\nnString getFullPath(const char *initialDir)\n{\n    nString rval;\n#ifdef VORB_OS_WINDOWS\n    char pathBuffer[1024];\n    _fullpath(pathBuffer, initialDir, 1024);\n#else//VORB_OS_WINDOWS\n    char pathBuffer[PATH_MAX];\n    realpath(initialDir, pathBuffer);\n#endif//VORB_OS_WINDOWS\n    rval = pathBuffer;\n    return rval;\n}\n\nvoid pError(const char *message)\n{\n    FILE *logFile = NULL;\n    SDL_SetRelativeMouseMode(SDL_FALSE);\n    logFile = fopen(\"errorlog.txt\", \"a+\");\n    if (logFile != NULL){\n        fprintf(logFile, \"*ERROR: %s \\n\", message);\n        fclose(logFile);\n    }\n    printf(\"*ERROR: %s \\n\", message);\n    fflush(stdout);\n    showMessage(\"ERROR: \" + nString(message));\n}\n\nvoid pError(const nString& message)\n{\n    FILE *logFile = NULL;\n    SDL_SetRelativeMouseMode(SDL_FALSE);\n    logFile = fopen(\"errorlog.txt\", \"a+\");\n    if (logFile != NULL){\n        fprintf(logFile, \"*ERROR: %s \\n\", message.c_str());\n        fclose(logFile);\n    }\n    printf(\"*ERROR: %s \\n\", message.c_str());\n    fflush(stdout);\n    showMessage(\"ERROR: \" + message);\n}\n\n//Checks the output of glGetError and prints an appropriate error message if needed.\nbool checkGlError(const nString& errorLocation) {\n    GLenum error = glGetError();\n    if (error != GL_NO_ERROR) {\n        switch (error) {\n        case GL_INVALID_ENUM:\n            pError(\"At \" + errorLocation + \". Error code 1280: GL_INVALID_ENUM\");\n            break;\n        case GL_INVALID_VALUE:\n            pError(\"At \" + errorLocation + \". Error code 1281: GL_INVALID_VALUE\");\n            break;\n        case GL_INVALID_OPERATION:\n            pError(\"At \" + errorLocation + \". Error code 1282: GL_INVALID_OPERATION\");\n            break;\n        case GL_STACK_OVERFLOW:\n            pError(\"At \" + errorLocation + \". Error code 1283: GL_STACK_OVERFLOW\");\n            break;\n        case GL_STACK_UNDERFLOW:\n            pError(\"At \" + errorLocation + \". Error code 1284: GL_STACK_UNDERFLOW\");\n            break;\n        case GL_OUT_OF_MEMORY:\n            pError(\"At \" + errorLocation + \". Error code 1285: GL_OUT_OF_MEMORY\");\n            break;\n        case GL_INVALID_FRAMEBUFFER_OPERATION:\n            pError(\"At \" + errorLocation + \". Error code 1285: GL_INVALID_FRAMEBUFFER_OPERATION\");\n            break;\n        default:\n            pError(\"At \" + errorLocation + \". Error code \" + std::to_string(error) + \": UNKNOWN\");\n            break;\n        }\n        return true;\n    }\n    return false;\n}\n"
  },
  {
    "path": "SoA/Errors.h",
    "content": "#pragma once\n\n#include \"Vorb/types.h\"\n\n//yes 1, no 0\nextern i32 showYesNoBox(const nString& message);\nextern i32 showYesNoCancelBox(const nString& message);\nextern void showMessage(const nString& message);\n\nextern nString getFullPath(const cString initialDir);\nextern void pError(const cString message);\nextern void pError(const nString& message);\n\nextern bool checkGlError(const nString& errorLocation);"
  },
  {
    "path": "SoA/ExposureCalcRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ExposureCalcRenderStage.h\"\n\n#include \"ShaderLoader.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GLRenderTarget.h>\n#include <Vorb/graphics/ShaderManager.h>\n#include <Vorb/graphics/SamplerState.h>\n#include <Vorb/script/IEnvironment.hpp>\n#include <Vorb/script/lua/Environment.h>\n\n#define EXPOSURE_FUNCTION_FILE \"Shaders/PostProcessing/exposure.lua\"\n#define EXPOSURE_FUNCTION_NAME \"calculateExposure\"\n\nExposureCalcRenderStage::ExposureCalcRenderStage() {\n    \n}\n\nExposureCalcRenderStage::~ExposureCalcRenderStage() {\n}\n\n\nvoid ExposureCalcRenderStage::hook(vg::FullQuadVBO* quad, vg::GBuffer* hdrFrameBuffer,\n                                   const ui32v4* viewPort, ui32 resolution) {\n    if(!m_env)\n    {\n        m_env=new vscript::lua::Environment();\n        m_env->init();\n    }\n\n    m_quad            = quad;\n    m_hdrFrameBuffer  = hdrFrameBuffer;\n    m_restoreViewport = viewPort;\n    m_resolution      = resolution;\n    ui32 size         = resolution;\n    m_mipLevels       = 1;\n\n    while (size > 1) {\n        m_mipLevels++;\n        size >>= 1;\n    }\n\n    m_mipStep = 0;\n}\n\nvoid ExposureCalcRenderStage::dispose(StaticLoadContext& context VORB_MAYBE_UNUSED) {\n    m_mipStep = 0;\n    if (m_program.isCreated()) m_program.dispose();\n    if (m_downsampleProgram.isCreated()) m_downsampleProgram.dispose();\n    for (size_t i = 0; i < m_renderTargets.size(); i++) {\n        m_renderTargets[i].dispose();\n    }\n    m_renderTargets.clear();\n    m_env->dispose();\n    delete m_env;\n    m_needsScriptLoad = true;\n}\n\nvoid ExposureCalcRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED /*= nullptr*/) {\n    if (m_renderTargets.empty()) {\n        m_renderTargets.resize(m_mipLevels);\n        for (size_t i = 0; i < m_mipLevels; i++) {\n            ui32 res = m_resolution >> i;\n            m_renderTargets[i].setSize(res, res);\n            m_renderTargets[i].init(vg::TextureInternalFormat::RGBA16F);\n        }    \n    }\n    // Lazy shader load\n    if (!m_program.isCreated()) {\n        m_program = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\",\n                                                        \"Shaders/PostProcessing/LogLuminance.frag\");\n        m_program.use();\n        glUniform1i(m_program.getUniform(\"unTex\"), 0);\n        m_program.unuse();\n    }\n    if (!m_downsampleProgram.isCreated()) {\n        m_downsampleProgram = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\",\n                                                        \"Shaders/PostProcessing/LumDownsample.frag\");\n        m_downsampleProgram.use();\n        glUniform1i(m_downsampleProgram.getUniform(\"unTex\"), 0);\n        m_downsampleProgram.unuse();\n    }\n    // Lazy script load\n    if (m_needsScriptLoad) {\n        m_env->run(nString(EXPOSURE_FUNCTION_FILE));\n        m_calculateExposure = m_env->template getScriptDelegate<f32, f32v4>(EXPOSURE_FUNCTION_NAME);\n        m_needsScriptLoad = false;\n    }\n\n    vg::GLProgram* prog = nullptr;\n    if (m_mipStep == (int)m_mipLevels-1) {\n        // Final Step\n        m_renderTargets[m_mipStep].bindTexture();\n        m_mipStep = 1;\n        f32v4 pixel = f32v4(0.0f);\n        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &pixel[0]);\n\n        // LUA SCRIPT\n#if defined(__GNUC__) && !defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n        m_exposure = m_calculateExposure(pixel);\n#pragma GCC diagnostic pop\n#else\n        m_exposure = m_calculateExposure(pixel);\n#endif\n\n        prog = &m_program;\n        m_hdrFrameBuffer->bindGeometryTexture(0, 0);\n    } else if (m_mipStep > 0) {\n        prog = &m_downsampleProgram;\n        m_renderTargets[m_mipStep].bindTexture();\n        m_mipStep++;\n    } else {\n        prog = &m_program;\n        m_hdrFrameBuffer->bindGeometryTexture(0, 0);\n        m_mipStep++;\n    }\n\n    glActiveTexture(GL_TEXTURE0);\n    // If we have rendered a frame before, generate mips and get lowest level\n\n    m_renderTargets[m_mipStep].use();\n\n    prog->use();\n    prog->enableVertexAttribArrays();\n\n    m_quad->draw();\n\n    prog->disableVertexAttribArrays();\n    prog->unuse();\n\n    m_renderTargets[m_mipStep].unuse(m_restoreViewport->z, m_restoreViewport->w);\n}\n"
  },
  {
    "path": "SoA/ExposureCalcRenderStage.h",
    "content": "///\n/// ExposureCalcRenderStage.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 30 Apr 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Calculates log luminance of a scene for tone mapping\n///\n\n#pragma once\n\n#ifndef ExposureCalcRenderStage_h__\n#define ExposureCalcRenderStage_h__\n\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GBuffer.h>\n\n#include \"IRenderStage.h\"\n\nDECL_VG(class GLProgram);\nDECL_VG(class GLRenderTarget);\nDECL_VSCRIPT(template <typename ScriptImpl> class IEnvironment; namespace lua { class Environment; });\n\nclass ExposureCalcRenderStage : public IRenderStage {\npublic:\n    ExposureCalcRenderStage();\n    ~ExposureCalcRenderStage();\n\n    /// resolution should be power of 2\n    void hook(vg::FullQuadVBO* quad, vg::GBuffer* hdrFrameBuffer,\n              const ui32v4* viewPort, ui32 resolution);\n\n    /// Disposes and deletes the shader and turns off visibility\n    /// If stage does lazy init, shader will reload at next draw\n    virtual void dispose(StaticLoadContext& context) override;\n\n    /// Draws the render stage\n    /// @pre no FBO is bound\n    virtual void render(const Camera* camera = nullptr) override;\n\n    void setFrameBuffer(vg::GBuffer* hdrFrameBuffer) { m_hdrFrameBuffer = hdrFrameBuffer; }\n\n    const f32& getExposure() const { return m_exposure; }\n\nprivate:\n    vg::GLProgram                   m_downsampleProgram;\n    std::vector<vg::GLRenderTarget> m_renderTargets; ///< All render targets\n    vg::FullQuadVBO*                m_quad              = nullptr;\n    vg::GBuffer*                    m_hdrFrameBuffer    = nullptr;\n    const ui32v4*                   m_restoreViewport;\n    ui32                            m_resolution;\n    ui32                            m_mipLevels         = 1;\n    int                             m_mipStep           = -1;\n    f32                             m_exposure          = 0.0005f;\n    vg::GLProgram                   m_program;\n\n    // Script for exposure calc\n    bool m_needsScriptLoad = true;\n    vscript::IEnvironment<vscript::lua::Environment>* m_env = nullptr;\n    Delegate<f32, f32v4> m_calculateExposure;\n};\n\n#endif // ExposureCalcRenderStage_h__\n"
  },
  {
    "path": "SoA/FarTerrainComponentRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FarTerrainComponentRenderer.h\"\n\n#include \"Camera.h\"\n#include \"PlanetGenData.h\"\n#include \"ShaderLoader.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"TerrainPatchMeshManager.h\"\n#include \"VoxelSpaceUtils.h\"\n\n#include <Vorb/graphics/ShaderManager.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/utils.h>\n\nFarTerrainComponentRenderer::~FarTerrainComponentRenderer() {\n    dispose();\n}\n\nvoid FarTerrainComponentRenderer::initGL() {\n    if (!m_farTerrainProgram.isCreated()) {\n        buildShaders();\n    }\n}\n\nvoid FarTerrainComponentRenderer::draw(const FarTerrainComponent& cmp,\n                                       const Camera* camera,\n                                       const f64v3& lightDir,\n                                       const f32 zCoef,\n                                       const SpaceLightComponent* spComponent VORB_MAYBE_UNUSED,\n                                       const AxisRotationComponent* arComponent,\n                                       const AtmosphereComponent* aComponent) {\n    // Get voxel position for quaternion calculation\n    VoxelPosition3D pos;\n    pos.pos = camera->getPosition();\n    pos.face = cmp.face;\n\n    f64v3 relativeCameraPos = camera->getPosition() * KM_PER_VOXEL;\n\n    // Calculate relative light position\n    f64v3 relLightDir = glm::inverse(arComponent->currentOrientation) * lightDir;\n    relLightDir = glm::inverse(VoxelSpaceUtils::calculateVoxelToSpaceQuat(pos, cmp.sphericalTerrainData->radius * VOXELS_PER_KM)) * relLightDir;\n    \n    // Sort meshes\n    cmp.meshManager->sortFarMeshes(relativeCameraPos);\n    // Draw far patches\n    if (cmp.alpha > 0.0f) {\n        cmp.meshManager->drawFarMeshes(relativeCameraPos, camera,\n                                       m_farTerrainProgram, m_farWaterProgram,\n                                       f32v3(relLightDir),\n                                       glm::min(cmp.alpha, 1.0f),\n                                       (f32)cmp.planetGenData->radius,\n                                       zCoef,\n                                       aComponent,\n                                       (cmp.alpha >= 1.0f));\n    }\n}\n\nvoid FarTerrainComponentRenderer::dispose() {\n    if (m_farTerrainProgram.isCreated()) m_farTerrainProgram.dispose();\n    if (m_farWaterProgram.isCreated()) m_farWaterProgram.dispose();\n}\n\nvoid FarTerrainComponentRenderer::buildShaders() {\n\n    m_farTerrainProgram = ShaderLoader::createProgramFromFile(\"Shaders/SphericalTerrain/FarTerrain.vert\",\n                                                              \"Shaders/SphericalTerrain/SphericalTerrain.frag\");\n    // Set constant uniforms\n    m_farTerrainProgram.use();\n    glUniform1i(m_farTerrainProgram.getUniform(\"unColorMap\"), 1);\n    glUniform1i(m_farTerrainProgram.getUniform(\"unGrassTexture\"), 2);\n    glUniform1i(m_farTerrainProgram.getUniform(\"unRockTexture\"), 3);\n    m_farTerrainProgram.unuse();\n\n    // Build water shader \n    m_farWaterProgram = ShaderLoader::createProgramFromFile(\"Shaders/SphericalTerrain/FarWater.vert\",\n                                                            \"Shaders/SphericalTerrain/SphericalWater.frag\");\n    // Set constant uniforms\n    m_farWaterProgram.use();\n    glUniform1i(m_farWaterProgram.getUniform(\"unNormalMap\"), 0);\n    glUniform1i(m_farWaterProgram.getUniform(\"unColorMap\"), 1);\n    m_farWaterProgram.unuse();\n}\n"
  },
  {
    "path": "SoA/FarTerrainComponentRenderer.h",
    "content": "///\n/// FarTerrainComponentRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 22 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renderer for far terrain patches\n///\n\n#pragma once\n\n#ifndef FarTerrainComponentRenderer_h__\n#define FarTerrainComponentRenderer_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/GLProgram.h>\n\nclass Camera;\nstruct AtmosphereComponent;\nstruct AxisRotationComponent;\nstruct FarTerrainComponent;\nstruct NamePositionComponent;\nstruct SpaceLightComponent;\nstruct SphericalTerrainComponent;\n\nclass FarTerrainComponentRenderer {\npublic:\n    ~FarTerrainComponentRenderer();\n    void initGL();\n    void draw(const FarTerrainComponent& cmp,\n              const Camera* camera,\n              const f64v3& lightDir,\n              const f32 zCoef,\n              const SpaceLightComponent* spComponent,\n              const AxisRotationComponent* arComponent,\n              const AtmosphereComponent* aComponent);\n    void dispose();\nprivate:\n    void buildShaders();\n\n    vg::GLProgram m_farTerrainProgram;\n    vg::GLProgram m_farWaterProgram;\n};\n\n#endif // FarTerrainComponentRenderer_h__\n"
  },
  {
    "path": "SoA/FarTerrainComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FarTerrainComponentUpdater.h\"\n\n#include \"FarTerrainPatch.h\"\n#include \"SpaceSystem.h\"\n#include \"SpaceSystemAssemblages.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"SphericalHeightmapGenerator.h\"\n#include \"TerrainPatchMeshManager.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"soaUtils.h\"\n\nvoid FarTerrainComponentUpdater::update(SpaceSystem* spaceSystem, const f64v3& cameraPos) {\n\n    for (auto& it : spaceSystem->farTerrain) {\n\n        FarTerrainComponent& cmp = it.second;\n\n        /// Calculate camera distance\n        f64 distance = glm::length(cameraPos);\n\n        // Update fading in and out animation\n        if (cmp.shouldFade) {\n            cmp.alpha -= TERRAIN_ALPHA_STEP;\n            if (cmp.alpha <= 0.0f) {\n                continue;\n            }\n        } else {\n            cmp.alpha += TERRAIN_ALPHA_STEP;\n            if (cmp.alpha > 1.0f) cmp.alpha = 1.0f;\n        }\n\n        // Check for transitioning to a new grid face\n        if (cmp.transitionFace != FACE_NONE) {\n            cmp.face = cmp.transitionFace;\n            cmp.transitionFace = FACE_NONE;\n            if (cmp.patches) {\n                delete[] cmp.patches;\n                cmp.patches = nullptr;\n            }\n        }\n\n        if (distance <= LOAD_DIST) {\n            // In range, allocate if needed\n            if (!cmp.patches) {\n                initPatches(cmp, cameraPos);\n            } else {\n                // Check to see if the grid should shift\n                const f64& patchWidth = (cmp.sphericalTerrainData->radius * 2.000) / FT_PATCH_ROW;\n                i32v2 newCenter(fastFloor(cameraPos.x / patchWidth), fastFloor(cameraPos.z / patchWidth));\n                checkGridShift(cmp, newCenter);\n            }\n\n            // Update patches\n            for (int i = 0; i < FT_TOTAL_PATCHES; i++) {\n                cmp.patches[i].update(cameraPos);\n            }      \n            \n        } else {\n            // Out of range, delete everything\n            if (cmp.patches) {\n                delete[] cmp.patches;\n                cmp.patches = nullptr;\n            }\n        }\n    }\n}\n\nvoid FarTerrainComponentUpdater::initPatches(FarTerrainComponent& cmp, const f64v3& cameraPos) {\n    const f64& patchWidth = (cmp.sphericalTerrainData->radius * 2.000) / FT_PATCH_ROW;\n\n    // Allocate top level patches\n    cmp.patches = new FarTerrainPatch[FT_TOTAL_PATCHES];\n\n    cmp.center.x = fastFloor(cameraPos.x / patchWidth);\n    cmp.center.y = fastFloor(cameraPos.z / patchWidth);\n\n    int centerX = FT_PATCH_ROW / 2 - cmp.center.x;\n    int centerZ = FT_PATCH_ROW / 2 - cmp.center.y;\n\n    f64v2 gridPos;\n    int index = 0;\n\n    // Init all the top level patches for each of the 6 grids\n\n    for (int z = 0; z < FT_PATCH_ROW; z++) {\n        for (int x = 0; x < FT_PATCH_ROW; x++) {\n            FarTerrainPatch& p = cmp.patches[index++];\n            gridPos.x = (x - centerX) * patchWidth;\n            gridPos.y = (z - centerZ) * patchWidth;\n            p.init(gridPos, cmp.face,\n                   0, cmp.sphericalTerrainData, patchWidth);\n        }\n    }\n}\n\nvoid FarTerrainComponentUpdater::glUpdate(SpaceSystem* spaceSystem) {\n    for (auto& it : spaceSystem->farTerrain) {\n        if (it.second.meshManager) it.second.meshManager->update();\n    }\n}\n\nvoid FarTerrainComponentUpdater::checkGridShift(FarTerrainComponent& cmp, const i32v2& newCenter) {\n    f64v2 gridPos;\n    const f64& patchWidth = (cmp.sphericalTerrainData->radius * 2.000) / FT_PATCH_ROW;\n    // X shift\n    if (newCenter.x > cmp.center.x) { // +X shift\n        // Shift center\n        cmp.center.x++;\n        // Destroy and re-init the leftmost column of chunks\n        i32 gx = cmp.origin.x;\n        for (i32 z = 0; z < FT_PATCH_ROW; z++) {\n            i32 gz = (cmp.origin.y + z) % FT_PATCH_ROW;\n            FarTerrainPatch& p = cmp.patches[gz * FT_PATCH_ROW + gx];\n            p.destroy();\n            gridPos.x = (cmp.center.x + FT_PATCH_ROW / 2 - 1) * patchWidth;\n            gridPos.y = (cmp.center.y + z - FT_PATCH_ROW / 2) * patchWidth;\n            p.init(gridPos, cmp.face,\n                   0, cmp.sphericalTerrainData, patchWidth);\n        }\n        // Shift origin\n        cmp.origin.x++;\n        // Origin is % FT_PATCH_ROW\n        if (cmp.origin.x >= FT_PATCH_ROW) cmp.origin.x = 0;\n        return;\n    } else if (newCenter.x < cmp.center.x) { // -X shift\n        // Shift center\n        cmp.center.x--;\n        // Destroy and re-init the rightmost column of chunks\n        i32 gx = (cmp.origin.x + FT_PATCH_ROW - 1) % FT_PATCH_ROW;\n        for (i32 z = 0; z < FT_PATCH_ROW; z++) {\n            i32 gz = (cmp.origin.y + z) % FT_PATCH_ROW;\n            FarTerrainPatch& p = cmp.patches[gz * FT_PATCH_ROW + gx];\n            p.destroy();\n            gridPos.x = (cmp.center.x - FT_PATCH_ROW / 2) * patchWidth;\n            gridPos.y = (cmp.center.y + z - FT_PATCH_ROW / 2) * patchWidth;\n            p.init(gridPos, cmp.face,\n                   0, cmp.sphericalTerrainData, patchWidth);\n        }\n        // Shift origin\n        cmp.origin.x--;\n        // Origin is % FT_PATCH_ROW\n        if (cmp.origin.x < 0) cmp.origin.x = FT_PATCH_ROW - 1;\n        return;\n    }\n\n    // Z shift\n    if (newCenter.y > cmp.center.y) { // +Z shift\n        // Shift center\n        cmp.center.y++;\n        // Destroy and re-init the leftmost column of chunks\n        i32 gz = cmp.origin.y;\n        for (int x = 0; x < FT_PATCH_ROW; x++) {\n            int gx = (cmp.origin.x + x) % FT_PATCH_ROW;\n            FarTerrainPatch& p = cmp.patches[gz * FT_PATCH_ROW + gx];\n            p.destroy();\n            gridPos.x = (cmp.center.x + x - FT_PATCH_ROW / 2) * patchWidth;\n            gridPos.y = (cmp.center.y + FT_PATCH_ROW / 2 - 1) * patchWidth;\n            p.init(gridPos, cmp.face,\n                   0, cmp.sphericalTerrainData, patchWidth);\n        }\n        // Shift origin\n        cmp.origin.y++;\n        // Origin is % FT_PATCH_ROW\n        if (cmp.origin.y >= FT_PATCH_ROW) cmp.origin.y = 0;\n    } else if (newCenter.y < cmp.center.y) { // -Z shift\n        // Shift center\n        cmp.center.y--;\n        // Destroy and re-init the rightmost column of chunks\n        i32 gz = (cmp.origin.y + FT_PATCH_ROW - 1) % FT_PATCH_ROW;\n        for (i32 x = 0; x < FT_PATCH_ROW; x++) {\n            int gx = (cmp.origin.x + x) % FT_PATCH_ROW;\n            FarTerrainPatch& p = cmp.patches[gz * FT_PATCH_ROW + gx];\n            p.destroy();\n            gridPos.x = (cmp.center.x + x - FT_PATCH_ROW / 2) * patchWidth;\n            gridPos.y = (cmp.center.y - FT_PATCH_ROW / 2) * patchWidth;\n            p.init(gridPos, cmp.face,\n                   0, cmp.sphericalTerrainData, patchWidth);\n        }\n        // Shift origin\n        cmp.origin.y--;\n        // Origin is % FT_PATCH_ROW\n        if (cmp.origin.y < 0) cmp.origin.y = FT_PATCH_ROW - 1;\n    }\n}\n"
  },
  {
    "path": "SoA/FarTerrainComponentUpdater.h",
    "content": "///\n/// FarTerrainComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 12 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updater for far terrain\n///\n\n#pragma once\n\n#ifndef FarTerrainComponentUpdater_h__\n#define FarTerrainComponentUpdater_h__\n\nclass SpaceSystem;\nstruct FarTerrainComponent;\n\n#include \"TerrainPatch.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"SphericalTerrainComponentUpdater.h\"\n#include <Vorb/vorb_rpc.h>\n\n#define FT_PATCH_ROW 16  \n#define NUM_FACES 6\nconst int FT_TOTAL_PATCHES = (FT_PATCH_ROW * FT_PATCH_ROW);\n\nclass FarTerrainComponentUpdater {\npublic:\n    void update(SpaceSystem* spaceSystem, const f64v3& cameraPos);\n\n    /// Updates openGL specific stuff. Call on render thread\n    void glUpdate(SpaceSystem* spaceSystem);\n\nprivate:\n    void initPatches(FarTerrainComponent& cmp, const f64v3& cameraPos);\n    // Checks and possibly shifts the far terrain patch grid to always center on the player\n    void checkGridShift(FarTerrainComponent& cmp, const i32v2& newCenter);\n};\n\n#endif // FarTerrainComponentUpdater_h__\n"
  },
  {
    "path": "SoA/FarTerrainPatch.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FarTerrainPatch.h\"\n\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/TextureRecycler.hpp>\n#include <Vorb/utils.h>\n\n#include \"Camera.h\"\n#include \"RenderUtils.h\"\n#include \"TerrainPatchMesher.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"VoxelSpaceConversions.h\"\n#include \"soaUtils.h\"\n\nFarTerrainPatch::~FarTerrainPatch() {\n    destroy();\n}\n\nvoid FarTerrainPatch::init(const f64v2& gridPosition, WorldCubeFace cubeFace, int lod, const TerrainPatchData* sphericalTerrainData, f64 width) {\n    m_gridPos = gridPosition;\n    m_cubeFace = cubeFace;\n    m_lod = lod;\n    m_terrainPatchData = sphericalTerrainData;\n    m_width = width;\n\n    // Get world position and bounding box\n    m_aabbPos = f32v3(m_gridPos.x, 0, m_gridPos.y);\n    m_aabbDims = f32v3(m_width, 0, m_width);\n}\n\nvoid FarTerrainPatch::update(const f64v3& cameraPos) {\n    // TODO(Matthew): This value is never used, check the function is behaving as expected.\n    //f64v3 closestPoint = calculateClosestPointAndDist(cameraPos);\n\n    if (m_children) {\n        if (m_distance > m_width * DIST_MAX) {\n            if (!m_mesh) {\n                requestMesh(false);\n            }\n            if (hasMesh()) {\n                // Out of range, kill children\n                delete[] m_children;\n                m_children = nullptr;\n            }\n        } else if (m_mesh) {\n            // In range, but we need to remove our mesh.\n            // Check to see if all children are renderable\n            bool deleteMesh = true;\n            for (int i = 0; i < 4; i++) {\n                if (!m_children[i].isRenderable()) {\n                    deleteMesh = false;\n                    break;\n                }\n            }\n\n            if (deleteMesh) {\n                // Children are renderable, free mesh.\n                // Render thread will deallocate.\n                m_mesh->m_shouldDelete = true;\n                m_mesh = nullptr;\n            }\n        }\n    } else if (m_lod < PATCH_MAX_LOD && m_distance < m_width * DIST_MIN && m_width > MIN_SIZE) {\n        m_children = new FarTerrainPatch[4];\n        // Segment into 4 children\n        for (int z = 0; z < 2; z++) {\n            for (int x = 0; x < 2; x++) {\n                m_children[(z << 1) + x].init(m_gridPos + f64v2((m_width / 2.0) * x, (m_width / 2.0) * z),\n                                                m_cubeFace, m_lod + 1, m_terrainPatchData, m_width / 2.0);\n            }\n        }\n    } else if (!m_mesh) {\n        requestMesh(false);\n    }\n\n    // Recursively update children if they exist\n    if (m_children) {\n        for (int i = 0; i < 4; i++) {\n            m_children[i].update(cameraPos);\n        }\n    }\n}\n\nbool FarTerrainPatch::isOverHorizon(const f64v3 &relCamPos, const f64v3 &point, f64 planetRadius) {\n    const f64 DELTA = 0.1;\n\n    // Position of point relative to sphere tip\n    f64v3 spherePoint = point - f64v3(relCamPos.x, -planetRadius, relCamPos.z);\n    // We assume the camera is at the tip of the sphere\n    f64v3 sphereCamPos(0, relCamPos.y + planetRadius, 0);\n\n    f64 camHeight = glm::length(sphereCamPos);\n    f64v3 normalizedCamPos = sphereCamPos / camHeight;\n\n    // Limit the camera depth\n    if (camHeight < planetRadius + 1.0) camHeight = planetRadius + 1.0;\n\n    f64 horizonAngle = acos(planetRadius / camHeight);\n    f64 lodAngle = acos(glm::dot(normalizedCamPos, glm::normalize(spherePoint)));\n    if (lodAngle >= horizonAngle + DELTA) {\n        return true;\n    }\n    return false;\n}\n"
  },
  {
    "path": "SoA/FarTerrainPatch.h",
    "content": "///\n/// FarTerrainPatch.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Defines a class for a patch of far-terrain\n///\n\n#pragma once\n\n#ifndef FarTerrainPatch_h__\n#define FarTerrainPatch_h__\n\n#include \"TerrainPatch.h\"\n\n// TODO(Ben): Linear fade to prevent LOD popping\nclass FarTerrainPatch : public TerrainPatch {\npublic:\n    FarTerrainPatch() {};\n    ~FarTerrainPatch();\n\n    /// Initializes the patch\n    /// @param gridPosition: Position on the 2d face grid\n    /// @param sphericalTerrainData: Shared data\n    /// @param width: Width of the patch in KM\n    void init(const f64v2& gridPosition,\n              WorldCubeFace cubeFace,\n              int lod,\n              const TerrainPatchData* sphericalTerrainData,\n              f64 width) override;\n\n    /// Updates the patch\n    /// @param cameraPos: Position of the camera\n    void update(const f64v3& cameraPos) override;\n\n    /// Checks if the point is over the horizon\n    /// @param relCamPos: Relative observer position\n    /// @param point: The point to check\n    /// @param planetRadius: Radius of the planet\n    static bool isOverHorizon(const f64v3 &relCamPos, const f64v3 &point, f64 planetRadius);\n};\n\n#endif // FarTerrainPatch_h__\n"
  },
  {
    "path": "SoA/Flora.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Flora.h\"\n\nKEG_ENUM_DEF(FloraInterpType, FloraInterpType, e) {\n    e.addValue(\"linear\", FloraInterpType::LINEAR);\n    e.addValue(\"lin\", FloraInterpType::LINEAR);\n    e.addValue(\"hermite\", FloraInterpType::HERMITE);\n    e.addValue(\"herm\", FloraInterpType::HERMITE);\n    e.addValue(\"cosine\", FloraInterpType::COSINE);\n    e.addValue(\"cos\", FloraInterpType::COSINE);\n    e.addValue(\"sine\", FloraInterpType::SINE);\n    e.addValue(\"sin\", FloraInterpType::SINE);\n}\n\nKEG_ENUM_DEF(TreeLeafType, TreeLeafType, e) {\n    e.addValue(\"none\", TreeLeafType::NONE);\n    e.addValue(\"round\", TreeLeafType::ROUND);\n    e.addValue(\"pine\", TreeLeafType::PINE);\n    e.addValue(\"mushroom\", TreeLeafType::MUSHROOM);\n}\n\nKEG_ENUM_DEF(FloraDir, FloraDir, e) {\n    e.addValue(\"up\", FloraDir::UP);\n    e.addValue(\"side\", FloraDir::SIDE);\n    e.addValue(\"down\", FloraDir::DOWN);\n}\n"
  },
  {
    "path": "SoA/Flora.h",
    "content": "///\n/// Flora.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 15 Jul 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Flora struct definitions.\n///\n\n#pragma once\n\n#ifndef Flora_h__\n#define Flora_h__\n\n#include <Vorb/io/Keg.h>\n#include <Vorb/utils.h>\n\n#define FLORA_ID_NONE 0xFFFFu\n// Both trees and flora share FloraID\ntypedef ui16 FloraID;\n\n/* TreeType is a breed of tree, TreeData is an individual tree.*/\n\nenum class FloraInterpType {\n    LINEAR,\n    HERMITE,\n    COSINE,\n    SINE\n};\nKEG_ENUM_DECL(FloraInterpType);\n\nenum class TreeLeafType {\n    NONE,\n    ROUND,\n    PINE,\n    MUSHROOM\n};\nKEG_ENUM_DECL(TreeLeafType);\n\nstruct TreeTypeFruitProperties {\n    FloraID flora = FLORA_ID_NONE;\n    Range<f32> chance;\n};\nstruct TreeFruitProperties {\n    FloraID flora = FLORA_ID_NONE;\n    f32 chance;\n};\n\nstruct TreeTypeLeafProperties {\n    TreeLeafType type;\n    TreeTypeFruitProperties fruitProps;\n    // Mutually exclusive union based on type\n    union {\n        UNIONIZE(struct {\n            Range<ui16> vRadius;\n            Range<ui16> hRadius;\n            ui16 blockID;\n        } round;);\n        UNIONIZE(struct {\n            Range<ui16> oRadius;\n            Range<ui16> iRadius;\n            Range<ui16> period;\n            ui16 blockID;\n        } pine;);\n        UNIONIZE(struct {\n            Range<ui16> tvRadius;\n            Range<ui16> thRadius;\n            Range<ui16> bvRadius;\n            Range<ui16> bhRadius;\n            Range<ui16> bLength;\n            Range<ui16> capWidth;\n            Range<ui16> gillWidth;\n            ui16 gillBlockID;\n            ui16 capBlockID;\n            FloraInterpType interp;\n        } mushroom;);\n    };\n};\nstruct TreeLeafProperties {\n    TreeLeafType type;\n    TreeFruitProperties fruitProps;\n    // Mutually exclusive union based on type\n    union {\n        UNIONIZE(struct {\n            ui16 vRadius;\n            ui16 hRadius;\n            ui16 blockID;\n        } round;);\n        UNIONIZE(struct {\n            ui16 oRadius;\n            ui16 iRadius;\n            ui16 period;\n            ui16 blockID;\n        } pine;);\n        UNIONIZE(struct {\n            ui16 tvRadius;\n            ui16 thRadius;\n            ui16 bvRadius;\n            ui16 bhRadius;\n            ui16 bLength;\n            ui16 capWidth;\n            ui16 gillWidth;\n            ui16 gillBlockID;\n            ui16 capBlockID;\n            FloraInterpType interp;\n        } mushroom;);\n    };\n};\n\nstruct TreeTypeBranchProperties {\n    Range<ui16> coreWidth;\n    Range<ui16> barkWidth;\n    Range<f32> widthFalloff;\n    Range<f32> branchChance;\n    Range<f32> angle;\n    Range<f32> subBranchAngle;\n    Range<f32> changeDirChance;\n    ui16 coreBlockID = 0;\n    ui16 barkBlockID = 0;\n    TreeTypeFruitProperties fruitProps;\n    TreeTypeLeafProperties leafProps;\n};\nstruct TreeBranchProperties {\n    f32 branchChance;\n    f32 widthFalloff;\n    f32 changeDirChance;\n    ui16 coreWidth;\n    ui16 barkWidth;\n    ui16 coreBlockID = 0;\n    ui16 barkBlockID = 0;\n    Range<f32> angle;\n    Range<f32> subBranchAngle;\n    TreeFruitProperties fruitProps;\n    TreeLeafProperties leafProps;\n};\n\nstruct TreeTypeTrunkProperties {\n    f32 loc;\n    Range<ui16> coreWidth;\n    Range<ui16> barkWidth;\n    Range<f32> branchChance;\n    Range<f32> changeDirChance;\n    Range<Range<i32>> slope;\n    ui16 coreBlockID = 0;\n    ui16 barkBlockID = 0;\n    FloraInterpType interp;\n    TreeTypeFruitProperties fruitProps;\n    TreeTypeLeafProperties leafProps;\n    TreeTypeBranchProperties branchProps;\n};\nstruct TreeTrunkProperties {\n    f32 loc;\n    ui16 coreWidth;\n    ui16 barkWidth;\n    f32 branchChance;\n    f32 changeDirChance;\n    i32 slope;\n    ui16 coreBlockID;\n    ui16 barkBlockID;\n    FloraInterpType interp;\n    TreeFruitProperties fruitProps;\n    TreeLeafProperties leafProps;\n    TreeBranchProperties branchProps;\n};\n\nstruct TreeTypeBranchVolumeProperties {\n    Range<ui16> height;\n    Range<ui16> hRadius;\n    Range<ui16> vRadius;\n    Range<ui16> points;\n};\nstruct BranchVolumeProperties {\n    ui16 height;\n    ui16 hRadius;\n    ui16 vRadius;\n    ui16 points;\n    f32 infRadius;\n};\n\nstruct NTreeType {\n    // All ranges are for scaling between baby tree and adult tree\n    Range<ui16> height;\n    Range<ui16> branchPoints;\n    Range<ui16> branchStep;\n    Range<ui16> killMult;\n    Range<f32> infRadius;\n    std::vector<TreeTypeBranchVolumeProperties> branchVolumes;\n    // Data points for trunk properties. Properties get interpolated between these from\n    // base of tree to top of tree.\n    std::vector<TreeTypeTrunkProperties> trunkProps;\n};\n\n// Specification for an individual tree\nstruct TreeData {\n    f32 age; ///< 0 - 1\n    ui16 height;\n    ui16 branchPoints;\n    ui16 branchStep;\n    ui16 killMult;\n    ui16 currentDir;\n    f32 infRadius;\n    std::vector<BranchVolumeProperties> branchVolumes;\n    std::vector<TreeTrunkProperties> trunkProps;\n};\n\nenum class FloraDir {\n    UP, SIDE, DOWN\n};\nKEG_ENUM_DECL(FloraDir);\n\nstruct FloraType {\n    ui16 block;\n    Range<ui16> height;\n    Range<ui16> slope;\n    Range<ui16> dSlope;\n    FloraDir dir;\n    const FloraType* nextFlora = nullptr;\n};\n\n// Specification for individual flora\nstruct FloraData {\n    ui16 block;\n    ui16 height;\n    ui16 dir;\n    ui16 slope;\n    ui16 dSlope;\n    const FloraType* nextFlora;\n};\n\n#endif // Flora_h__\n"
  },
  {
    "path": "SoA/FloraGenerator.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FloraGenerator.h\"\n\n#define X_1 0x100000\n#define Y_1 0x400\n#define Z_1 0x1\n\n#define OUTER_SKIP_MOD 5\n\n#ifdef VORB_OS_WINDOWS\n#pragma region helpers\n#endif//VORB_OS_WINDOWS\n/************************************************************************/\n/* Helper Functions                                                     */\n/************************************************************************/\n/*  These functions allow us to move in chunk-space without branching.  */\n/************************************************************************/\n// Adds a positive offset\ninline void offsetPositive(int& x, int x1, ui32& chunkOffset, int offset) {\n    x += offset;\n    chunkOffset += x1 * (x / CHUNK_WIDTH);\n    x &= 0x1f; // Modulo 32\n}\ninline void offsetNegative(int& x, int x1, ui32& chunkOffset, int offset) {\n    // We are inverting and treating negative as positive here so modulus works\n    // without branching\n    x = (CHUNK_WIDTH_M1 - x) + offset;\n    chunkOffset -= x1 * (x / CHUNK_WIDTH);\n    // Modulo 32 and invert back to positive\n    x = CHUNK_WIDTH_M1 - (x & 0x1f);\n}\ninline void offsetNegative(int& x, int& y, int x1, int y1, ui32& chunkOffset, int offset) {\n    // We are inverting and treating negative as positive here so modulus works\n    // without branching\n    x = (CHUNK_WIDTH_M1 - x) + offset;\n    y = (CHUNK_WIDTH_M1 - y) + offset;\n    chunkOffset -= x1 * (x / CHUNK_WIDTH);\n    chunkOffset -= y1 * (y / CHUNK_WIDTH);\n    // Modulo 32 and invert back to positive\n    x = CHUNK_WIDTH_M1 - (x & 0x1f);\n    y = CHUNK_WIDTH_M1 - (y & 0x1f);\n}\ninline void offsetNegative(int& x, int& y, int& z, ui32& chunkOffset, int offset) {\n    // We are inverting and treating negative as positive here so modulus works\n    // without branching\n    x = (CHUNK_WIDTH_M1 - x) + offset;\n    y = (CHUNK_WIDTH_M1 - y) + offset;\n    z = (CHUNK_WIDTH_M1 - z) + offset;\n    chunkOffset -= X_1 * (x / CHUNK_WIDTH);\n    chunkOffset -= Y_1 * (y / CHUNK_WIDTH);\n    chunkOffset -= Z_1 * (z / CHUNK_WIDTH);\n    // Modulo 32 and invert back to positive\n    x = CHUNK_WIDTH_M1 - (x & 0x1f);\n    y = CHUNK_WIDTH_M1 - (y & 0x1f);\n    z = CHUNK_WIDTH_M1 - (z & 0x1f);\n}\ninline void addChunkOffset(i32v2& pos, ui32& chunkOffset) {\n    // Modify chunk offset\n    chunkOffset += X_1 * (pos.x / CHUNK_WIDTH);\n    chunkOffset += Z_1 * (pos.y / CHUNK_WIDTH);\n    pos &= 0x1f; // Modulo 32\n}\ninline void addChunkOffset(i32v3& pos, ui32& chunkOffset) {\n    // Modify chunk offset\n    chunkOffset += X_1 * (pos.x / CHUNK_WIDTH);\n    chunkOffset += Y_1 * (pos.y / CHUNK_WIDTH);\n    chunkOffset += Z_1 * (pos.z / CHUNK_WIDTH);\n    // Modulo 32\n    pos &= 0x1f; // Modulo 32\n}\n\ninline void offsetAxis(int& x, int x1, ui32& chunkOffset, int offset) {\n    if (offset < 0) {\n        x = (CHUNK_WIDTH_M1 - x) - offset;\n        chunkOffset -= x1 * (x / CHUNK_WIDTH);\n        x = CHUNK_WIDTH_M1 - (x & 0x1f);\n    } else {\n        x = x + offset;\n        chunkOffset += x1 * (x / CHUNK_WIDTH);\n        x &= 0x1f;\n    }\n}\n\n// Offsets by a floating point position\ninline void offsetByPos(int& x, int& y, int& z, ui32& chunkOffset, const f32v3& pos) {\n    if (pos.x < 0.0f) {\n        x = (CHUNK_WIDTH_M1 - x) - fastFloor(pos.x);\n        chunkOffset -= X_1 * (x / CHUNK_WIDTH);\n        x = CHUNK_WIDTH_M1 - (x & 0x1f);\n    } else {\n        x = x + (int)pos.x;\n        chunkOffset += X_1 * (x / CHUNK_WIDTH);\n        x &= 0x1f;\n    }\n    if (pos.y < 0.0f) {\n        y = (CHUNK_WIDTH_M1 - y) - fastFloor(pos.y);\n        chunkOffset -= Y_1 * (y / CHUNK_WIDTH);\n        y = CHUNK_WIDTH_M1 - (y & 0x1f);\n    } else {\n        y = y + (int)pos.y;\n        chunkOffset += Y_1 * (y / CHUNK_WIDTH);\n        y &= 0x1f;\n    }\n    if (pos.z < 0.0f) {\n        z = (CHUNK_WIDTH_M1 - z) - fastFloor(pos.z);\n        chunkOffset -= Z_1 * (z / CHUNK_WIDTH);\n        z = CHUNK_WIDTH_M1 - (z & 0x1f);\n    } else {\n        z = z + (int)pos.z;\n        chunkOffset += Z_1 * (z / CHUNK_WIDTH);\n        z &= 0x1f;\n    }\n}\ninline void offsetByPos(int& x, int& y, int& z, ui32& chunkOffset, const i32v3& pos) {\n    if (pos.x < 0) {\n        x = (CHUNK_WIDTH_M1 - x) - pos.x;\n        chunkOffset -= X_1 * (x / CHUNK_WIDTH);\n        x = CHUNK_WIDTH_M1 - (x & 0x1f);\n    } else {\n        x = x + pos.x;\n        chunkOffset += X_1 * (x / CHUNK_WIDTH);\n        x &= 0x1f;\n    }\n    if (pos.y < 0) {\n        y = (CHUNK_WIDTH_M1 - y) - pos.y;\n        chunkOffset -= Y_1 * (y / CHUNK_WIDTH);\n        y = CHUNK_WIDTH_M1 - (y & 0x1f);\n    } else {\n        y = y + pos.y;\n        chunkOffset += Y_1 * (y / CHUNK_WIDTH);\n        y &= 0x1f;\n    }\n    if (pos.z < 0) {\n        z = (CHUNK_WIDTH_M1 - z) - pos.z;\n        chunkOffset -= Z_1 * (z / CHUNK_WIDTH);\n        z = CHUNK_WIDTH_M1 - (z & 0x1f);\n    } else {\n        z = z + pos.z;\n        chunkOffset += Z_1 * (z / CHUNK_WIDTH);\n        z &= 0x1f;\n    }\n}\n/************************************************************************/\n/* End Helper Functions                                                 */\n/************************************************************************/\n#ifdef VORB_OS_WINDOWS\n#pragma endregion\n#endif//VORB_OS_WINDOWS\n\n// Smooths an input factor on the range 0-1\ninline void smoothInterpFactor(f32& l, const FloraInterpType& type) {\n    switch (type) {\n        case FloraInterpType::HERMITE:\n            l = hermite(l);\n            break;\n        case FloraInterpType::COSINE:\n            // TODO(Ben): cos lookup table\n            l = (f32)(1.0 - cos((f64)l * M_PI_2));\n            break;\n        case FloraInterpType::SINE:\n            // TODO(Ben): sin lookup table\n            l = (f32)(sin((f64)l * M_PI_2));\n            break;\n        default:\n            break;\n    }\n}\n\nvoid FloraGenerator::generateChunkFlora(const Chunk* chunk, const PlanetHeightData* heightData, OUT std::vector<FloraNode>& fNodes, OUT std::vector<FloraNode>& wNodes) {\n    // Iterate all block indices where flora must be generated\n    for (ui16 blockIndex : chunk->floraToGenerate) {\n        // Get position\n        m_center.x = blockIndex & 0x1F; // & 0x1F = % 32\n        m_center.y = blockIndex / CHUNK_LAYER;\n        m_center.z = (blockIndex & 0x3FF) / CHUNK_WIDTH; // & 0x3FF = % 1024\n        const PlanetHeightData& hd = heightData[blockIndex & 0x3FF]; // & 0x3FF = % CHUNK_LAYER\n        const Biome* b = hd.biome;\n        // Seed the generator\n        const VoxelPosition3D& vpos = chunk->getVoxelPosition();\n        m_rGen.seed(vpos.pos.x + m_center.x, vpos.pos.y + m_center.y, vpos.pos.z + m_center.z);\n        // Get age\n        f32 age = (f32)m_rGen.genlf();\n        // Determine which to generate\n        if (hd.flora < b->flora.size()) {\n            // It's a flora\n            generateFlora(b->flora[hd.flora].data, age, fNodes, wNodes, NO_CHUNK_OFFSET, blockIndex);\n        } else {\n            // It's a tree\n            generateTree(b->trees[hd.flora - b->flora.size()].data, age, fNodes, wNodes, b->genData, NO_CHUNK_OFFSET, blockIndex);\n        }\n    }\n}\n\n#ifdef VORB_OS_WINDOWS\n#pragma region lerping\n#endif//VORB_OS_WINDOWS\n\n// Lerps and rounds\n#define LERP_UI16(var) FastConversion<f32, ui16>::floor((b.var - a.var) * l + a.var + 0.5f)\n#define LERP_I32(var) fastFloor((f32)(b.var - a.var) * l + (f32)a.var + 0.5f)\n\ninline void lerpFruitProperties(TreeFruitProperties& rvProps, const TreeFruitProperties& a, const TreeFruitProperties& b, f32 l) {\n    rvProps.chance = lerp(a.chance, b.chance, l);\n    if (l < 0.5) {\n        rvProps.flora = a.flora;\n    } else {\n        rvProps.flora = b.flora;\n    }\n}\n\ninline void lerpLeafProperties(TreeLeafProperties& rvProps, const TreeLeafProperties& a, const TreeLeafProperties& b, f32 l) {\n    const TreeLeafProperties* blockP;\n    if (l < 0.5f) {\n        blockP = &a;\n    } else {\n        blockP = &b;\n    }\n    rvProps.type = blockP->type;\n    switch (rvProps.type) {\n        case TreeLeafType::ROUND:\n            rvProps.round.blockID = blockP->round.blockID;\n            if (a.type == b.type) {\n                rvProps.round.vRadius = LERP_UI16(round.vRadius);\n                rvProps.round.hRadius = LERP_UI16(round.hRadius);\n            } else {\n                rvProps.round.vRadius = blockP->round.vRadius;\n                rvProps.round.hRadius = blockP->round.hRadius;\n            }\n            break;\n        case TreeLeafType::PINE:\n            rvProps.pine.blockID = blockP->pine.blockID;\n            if (a.type == b.type) {\n                rvProps.pine.oRadius = LERP_UI16(pine.oRadius);\n                rvProps.pine.iRadius = LERP_UI16(pine.iRadius);\n                rvProps.pine.period = LERP_UI16(pine.period);\n            } else {\n                rvProps.pine.oRadius = blockP->pine.oRadius;\n                rvProps.pine.iRadius = blockP->pine.iRadius;\n                rvProps.pine.period = blockP->pine.period;\n            }\n            break;\n        case TreeLeafType::MUSHROOM:\n            rvProps.mushroom.capBlockID = blockP->mushroom.capBlockID;\n            rvProps.mushroom.gillBlockID = blockP->mushroom.gillBlockID;\n            rvProps.mushroom.interp = blockP->mushroom.interp;\n            if (a.type == b.type) {\n                rvProps.mushroom.tvRadius = LERP_UI16(mushroom.tvRadius);\n                rvProps.mushroom.thRadius = LERP_UI16(mushroom.thRadius);\n                rvProps.mushroom.bvRadius = LERP_UI16(mushroom.bvRadius);\n                rvProps.mushroom.bhRadius = LERP_UI16(mushroom.bhRadius);\n                rvProps.mushroom.bLength = LERP_UI16(mushroom.bLength);\n                rvProps.mushroom.capWidth = LERP_UI16(mushroom.capWidth);\n                rvProps.mushroom.gillWidth = LERP_UI16(mushroom.gillWidth);\n            } else {\n                rvProps.mushroom.tvRadius = blockP->mushroom.tvRadius;\n                rvProps.mushroom.thRadius = blockP->mushroom.thRadius;\n                rvProps.mushroom.bvRadius = blockP->mushroom.bvRadius;\n                rvProps.mushroom.bhRadius = blockP->mushroom.bhRadius;\n                rvProps.mushroom.bLength = blockP->mushroom.bLength;\n                rvProps.mushroom.capWidth = blockP->mushroom.capWidth;\n                rvProps.mushroom.gillWidth = blockP->mushroom.gillWidth;\n            }\n            break;\n        default:\n            break;\n    }\n    lerpFruitProperties(rvProps.fruitProps, a.fruitProps, b.fruitProps, l);\n}\n\ninline void lerpBranchProperties(TreeBranchProperties& rvProps, const TreeBranchProperties& a, const TreeBranchProperties& b, f32 l) {\n    // Block IDs\n    if (l < 0.5f) {\n        rvProps.barkBlockID = a.barkBlockID;\n        rvProps.coreBlockID = a.coreBlockID;\n    } else {\n        rvProps.barkBlockID = b.barkBlockID;\n        rvProps.coreBlockID = b.coreBlockID;\n    }\n    // Lerp the rest\n    rvProps.coreWidth = LERP_UI16(coreWidth);\n    rvProps.barkWidth = LERP_UI16(barkWidth);\n    rvProps.branchChance = lerp(a.branchChance, b.branchChance, l);\n    rvProps.changeDirChance = lerp(a.changeDirChance, b.changeDirChance, l);\n    rvProps.widthFalloff = lerp(a.widthFalloff, b.widthFalloff, l);\n    if (rvProps.widthFalloff == 0.0f) rvProps.widthFalloff = 0.1f; // Avoid div by zero\n    rvProps.angle.min = lerp(a.angle.min, b.angle.min, l);\n    rvProps.angle.max = lerp(a.angle.max, b.angle.max, l);\n    rvProps.subBranchAngle.min = lerp(a.subBranchAngle.min, b.subBranchAngle.min, l);\n    rvProps.subBranchAngle.max = lerp(a.subBranchAngle.max, b.subBranchAngle.max, l);\n    lerpLeafProperties(rvProps.leafProps, a.leafProps, b.leafProps, l);\n    lerpFruitProperties(rvProps.fruitProps, a.fruitProps, b.fruitProps, l);\n}\n\ninline void lerpTrunkProperties(TreeTrunkProperties& rvProps, const TreeTrunkProperties& a, const TreeTrunkProperties& b, f32 heightRatio) {\n    // TODO(Ben): Other interpolation types\n    f32 l = (heightRatio - a.loc) / (b.loc - a.loc);\n    // Hermite interpolation for smooth curve\n    smoothInterpFactor(l, a.interp);\n    rvProps.interp = a.interp;\n\n    // Block IDs\n    if (l < 0.5f) {\n        rvProps.barkBlockID = a.barkBlockID;\n        rvProps.coreBlockID = a.coreBlockID;\n    } else {\n        rvProps.barkBlockID = b.barkBlockID;\n        rvProps.coreBlockID = b.coreBlockID;\n    }\n    // Lerp the rest\n    rvProps.coreWidth = LERP_UI16(coreWidth);\n    rvProps.barkWidth = LERP_UI16(barkWidth);\n    rvProps.branchChance = lerp(a.branchChance, b.branchChance, l);\n    rvProps.changeDirChance = lerp(a.changeDirChance, b.changeDirChance, l);\n    rvProps.slope = LERP_I32(slope);\n    lerpBranchProperties(rvProps.branchProps, a.branchProps, b.branchProps, l);\n    lerpLeafProperties(rvProps.leafProps, a.leafProps, b.leafProps, l);\n    lerpFruitProperties(rvProps.fruitProps, a.fruitProps, b.fruitProps, l);\n}\n\nstruct DirLookup {\n    int axis;\n    int one;\n    int sign;\n};\nconst DirLookup DIR_AXIS_LOOKUP[4] = { {0, X_1, -1}, {2, Z_1, -1}, {0, X_1, 1}, {2, Z_1, 1} };\n\nvoid FloraGenerator::generateTree(const NTreeType* type, f32 age, OUT std::vector<FloraNode>& fNodes, OUT std::vector<FloraNode>& wNodes, const PlanetGenData* genData, ui32 chunkOffset /*= NO_CHUNK_OFFSET*/, ui16 blockIndex /*= 0*/) {\n    // Get the properties for this tree\n    // TODO(Ben): Temp\n    m_genData = genData;\n    age = 1.0f;\n    m_currChunkOff = 0;\n    generateTreeProperties(type, age, m_treeData);\n    m_nodeFields.reserve(m_treeData.height / CHUNK_WIDTH + 3);\n    m_nodeFieldsMap.reserve(200);\n    // Get handles\n    m_wNodes = &wNodes;\n    m_fNodes = &fNodes;\n\n    f32v3 m_startPos = f32v3(m_center) +\n        f32v3(CHUNK_WIDTH * getChunkXOffset(chunkOffset),\n        CHUNK_WIDTH * getChunkYOffset(chunkOffset),\n        CHUNK_WIDTH * getChunkZOffset(chunkOffset));\n\n    // Interpolated trunk properties\n    TreeTrunkProperties lerpedTrunkProps;\n    const TreeTrunkProperties* trunkProps = nullptr;\n\n    { // Generate the trunk\n        int scNodeStep = m_treeData.height / m_treeData.branchPoints;\n        if (scNodeStep == 0) scNodeStep = INT_MAX; // Prevent div by 0\n        int scNodeOffset = m_treeData.height % scNodeStep;\n\n        ui32 pointIndex = 0;\n        for (m_h = 0; m_h < m_treeData.height; ++m_h) {\n            // Get height ratio for interpolation purposes\n            f32 heightRatio = (f32)m_h / m_treeData.height;\n            // Do interpolation along data points\n            if (pointIndex < m_treeData.trunkProps.size() - 1) {\n                if (heightRatio > m_treeData.trunkProps[pointIndex + 1].loc) {\n                    ++pointIndex;\n                    if (pointIndex < m_treeData.trunkProps.size() - 1) {\n                        lerpTrunkProperties(lerpedTrunkProps, m_treeData.trunkProps[pointIndex], m_treeData.trunkProps[pointIndex + 1], heightRatio);\n                        trunkProps = &lerpedTrunkProps;\n                    } else {\n                        // Don't need to interpolate if we are at the last data point\n                        trunkProps = &m_treeData.trunkProps.back();\n                    }\n                } else {\n                    lerpTrunkProperties(lerpedTrunkProps, m_treeData.trunkProps[pointIndex], m_treeData.trunkProps[pointIndex + 1], heightRatio);\n                    trunkProps = &lerpedTrunkProps;\n                }\n            } else {\n                // Don't need to interpolate if we are at the last data point\n                trunkProps = &m_treeData.trunkProps.back();\n            }\n            // Check for potential branch point\n            m_hasStoredTrunkProps = false;\n            if ((m_h + scNodeOffset) % scNodeStep == 0) {\n                f32 width = (f32)(trunkProps->branchProps.coreWidth + trunkProps->branchProps.barkWidth);\n                if (width > 0.0f) {\n                    m_scNodes.emplace_back(m_scRayNodes.size());\n                    m_scRayNodes.emplace_back(f32v3(m_center) +\n                                              f32v3(CHUNK_WIDTH * getChunkXOffset(chunkOffset),\n                                              CHUNK_WIDTH * getChunkYOffset(chunkOffset),\n                                              CHUNK_WIDTH * getChunkZOffset(chunkOffset)),\n                                              SC_NO_PARENT,\n                                              m_scTrunkProps.size());\n                    m_scTrunkProps.push_back(*trunkProps);\n                    m_hasStoredTrunkProps = true;\n                }\n            }\n            // Build the trunk slice\n            makeTrunkSlice(chunkOffset, *trunkProps);\n            // Move up\n            offsetPositive(m_center.y, Y_1, chunkOffset, 1);\n            // Check for dir chance\n            if (m_rGen.genlf() <= trunkProps->changeDirChance) {\n                m_treeData.currentDir = m_rGen.gen() & 3; // & 3 == % 4\n            }\n            // Move sideways with slope if needed\n            if (m_h % trunkProps->slope == (unsigned int)(trunkProps->slope - 1)) {\n                // Place a block so we don't have any floating parts when width is 1\n                if (trunkProps->coreWidth + trunkProps->barkWidth == 1) {\n                    if (trunkProps->coreWidth) {\n                        ui16 blockIndex = (ui16)(m_center.x + m_center.y * CHUNK_LAYER + m_center.z * CHUNK_WIDTH);\n                        tryPlaceNode(m_wNodes, 3, trunkProps->coreBlockID, blockIndex, chunkOffset);\n                    } else {\n                        ui16 blockIndex = (ui16)(m_center.x + m_center.y * CHUNK_LAYER + m_center.z * CHUNK_WIDTH);\n                        tryPlaceNode(m_wNodes, 3, trunkProps->barkBlockID, blockIndex, chunkOffset);\n                    }\n                }\n                const DirLookup& dir = DIR_AXIS_LOOKUP[m_treeData.currentDir];\n                offsetAxis(m_center[dir.axis], dir.one, chunkOffset, dir.sign);\n            }\n        }\n    }\n    if (trunkProps->leafProps.type == TreeLeafType::MUSHROOM) {\n        generateMushroomCap(chunkOffset, m_center.x, m_center.y, m_center.z, trunkProps->leafProps);\n    }\n\n    // Branches\n    if (m_treeData.branchVolumes.size()) {\n        spaceColonization(m_startPos);\n        std::vector<SCTreeNode>().swap(m_scNodes);\n    }\n\n    // Generate deferred branches so they don't conflict with space colonization\n    for (auto& it : m_branchesToGenerate) {\n        TreeBranchProperties& bp = m_scTrunkProps[it.trunkPropsIndex].branchProps;\n        // Defer branching so it doesn't conflict with SC\n        f32 angle = (f32)(m_rGen.genlf() * (bp.angle.max - bp.angle.min) + bp.angle.min);\n        // Interpolate the angle\n        f32v3 dir = glm::normalize(lerp(glm::normalize(f32v3(it.dx, 0.0f, it.dz)), f32v3(0.0f, 1.0f, 0.0f), angle / M_PI_2F));\n        f32 width = (f32)(bp.coreWidth + bp.barkWidth);\n        f32 length = width / bp.widthFalloff;\n        // Determine float position\n        f32v3 pos;\n        pos.x = (f32)((it.blockIndex & 0x1F) + getChunkXOffset(it.chunkOffset) * CHUNK_WIDTH); // & 0x1F = % 32\n        pos.y = (f32)(it.blockIndex / CHUNK_LAYER + getChunkYOffset(it.chunkOffset) * CHUNK_WIDTH);\n        pos.z = (f32)((it.blockIndex & 0x3FF) / CHUNK_WIDTH + getChunkZOffset(it.chunkOffset) * CHUNK_WIDTH); // & 0x3FF = % 1024\n        // Add root\n        ui16 parent = m_scRayNodes.size();\n        m_scRayNodes.emplace_back(pos, SC_NO_PARENT, it.trunkPropsIndex);\n        // Determine chain length\n        int numSegments = (int)(length * bp.changeDirChance);\n        numSegments++;\n        length /= numSegments;\n        // Create branch chain\n        int i = 0;\n        while (true) {\n            pos += dir * length;\n            m_scRayNodes.emplace_back(pos, parent, it.trunkPropsIndex);\n            // Check end condition\n            if (++i == numSegments) break;\n            // Get new dir\n            newDirFromAngle(dir, bp.angle.min, bp.angle.max);\n            parent = m_scRayNodes.size() - 1;\n            if (parent >= 32767) {\n                break;\n            }\n        }\n        // Last node is leaf\n        m_scLeafSet.insert(m_scRayNodes.size() - 1);\n    }\n\n    // Place nodes for branches\n    if (m_scRayNodes.size()) {\n        generateSCBranches();\n        std::vector<SCRayNode>().swap(m_scRayNodes);\n        std::set<ui32>().swap(m_scLeafSet);\n    }\n\n    // Place leaves last to prevent node overlap\n    for (auto& it : m_leavesToPlace) {\n        m_center.x = blockIndex & 0x1F; // & 0x1F = % 32\n        m_center.y = blockIndex / CHUNK_LAYER;\n        m_center.z = (blockIndex & 0x3FF) / CHUNK_WIDTH; // & 0x3FF = % 1024\n        generateLeaves(it.chunkOffset, it.blockIndex & 0x1F,\n                       it.blockIndex / CHUNK_LAYER,\n                       (it.blockIndex & 0x3FF) / CHUNK_WIDTH,\n                       *it.leafProps);\n\n    }\n    \n    // Clear container memory\n    std::vector<LeavesToPlace>().swap(m_leavesToPlace);\n    std::vector<BranchToGenerate>().swap(m_branchesToGenerate);\n    std::vector<TreeTrunkProperties>().swap(m_scTrunkProps);\n    std::unordered_map<ui32, ui32>().swap(m_nodeFieldsMap);\n    std::vector<NodeField>().swap(m_nodeFields);\n}\n\nvoid FloraGenerator::generateFlora(const FloraType* type, f32 age, OUT std::vector<FloraNode>& fNodes, OUT std::vector<FloraNode>& wNodes VORB_UNUSED, ui32 chunkOffset /*= NO_CHUNK_OFFSET*/, ui16 blockIndex /*= 0*/) {\n    FloraData data;\n    generateFloraProperties(type, age, data);\n\n    // Get position\n    int x = blockIndex & 0x1F; // & 0x1F = % 32\n    int y = blockIndex / CHUNK_LAYER;\n    int z = (blockIndex & 0x3FF) / CHUNK_WIDTH; // & 0x3FF = % 1024\n\n    do {\n        if (data.dir == TREE_UP) {\n            for (m_h = 0; m_h < data.height; ++m_h) {\n                fNodes.emplace_back(data.block, blockIndex, chunkOffset);\n                // Move up\n                offsetPositive(y, Y_1, chunkOffset, 1);\n                blockIndex = x + y * CHUNK_LAYER + z * CHUNK_WIDTH;\n            }\n        } else if (data.dir == TREE_DOWN) {\n            for (m_h = 0; m_h < data.height; ++m_h) {\n                fNodes.emplace_back(data.block, blockIndex, chunkOffset);\n                // Move up\n                offsetNegative(y, Y_1, chunkOffset, 1);\n                blockIndex = x + y * CHUNK_LAYER + z * CHUNK_WIDTH;\n            }\n        } else {\n            // TODO(Ben): Implement\n        }\n        // Go on to sub flora if one exists\n        if (data.nextFlora) {\n            generateFloraProperties(data.nextFlora, age, data);\n        } else {\n            break;\n        }\n    } while (true);\n}\n#undef LERP_UI16\n#undef LERP_I32\n\n#ifdef VORB_OS_WINDOWS\n#pragma endregion\n\n#pragma region age_lerping\n#endif//VORB_OS_WINDOWS\n\n#define AGE_LERP_F32(var) lerp(var.max, var.min, age)\n// Lerps and rounds\n#define AGE_LERP_I32(var) fastFloor((f32)(var.max - var.min) * age + (f32)var.min + 0.5f)\n#define AGE_LERP_UI16(var) FastConversion<f32, ui16>::floor((f32)(var.max - var.min) * age + (f32)var.min + 0.5f)\n\ninline void setFruitProps(TreeFruitProperties& fruitProps, const TreeTypeFruitProperties& typeProps, f32 age) {\n    fruitProps.chance = AGE_LERP_F32(typeProps.chance);\n    fruitProps.flora = typeProps.flora;\n}\n\ninline void setLeafProps(TreeLeafProperties& leafProps, const TreeTypeLeafProperties& typeProps, f32 age) {\n    setFruitProps(leafProps.fruitProps, typeProps.fruitProps, age);\n    leafProps.type = typeProps.type;\n    switch (leafProps.type) {\n        case TreeLeafType::ROUND:\n            leafProps.round.blockID = typeProps.round.blockID;\n            leafProps.round.vRadius = AGE_LERP_UI16(typeProps.round.vRadius);\n            leafProps.round.hRadius = AGE_LERP_UI16(typeProps.round.hRadius);\n            break;\n        case TreeLeafType::PINE:\n            leafProps.pine.blockID = typeProps.pine.blockID;\n            leafProps.pine.oRadius = AGE_LERP_UI16(typeProps.pine.oRadius);\n            leafProps.pine.iRadius = AGE_LERP_UI16(typeProps.pine.iRadius);\n            leafProps.pine.period = AGE_LERP_UI16(typeProps.pine.period);\n            break;\n        case TreeLeafType::MUSHROOM:\n            leafProps.mushroom.capBlockID = typeProps.mushroom.capBlockID;\n            leafProps.mushroom.gillBlockID = typeProps.mushroom.gillBlockID;\n            leafProps.mushroom.interp = typeProps.mushroom.interp;\n            leafProps.mushroom.tvRadius = AGE_LERP_UI16(typeProps.mushroom.tvRadius);\n            leafProps.mushroom.thRadius = AGE_LERP_UI16(typeProps.mushroom.thRadius);\n            leafProps.mushroom.bvRadius = AGE_LERP_UI16(typeProps.mushroom.bvRadius);\n            leafProps.mushroom.bhRadius = AGE_LERP_UI16(typeProps.mushroom.bhRadius);\n            leafProps.mushroom.bLength = AGE_LERP_UI16(typeProps.mushroom.bLength);\n            leafProps.mushroom.capWidth = AGE_LERP_UI16(typeProps.mushroom.capWidth);\n            leafProps.mushroom.gillWidth = AGE_LERP_UI16(typeProps.mushroom.gillWidth);\n            break;\n        default:\n            break;\n    }\n}\n\ninline void setBranchProps(TreeBranchProperties& branchProps, const TreeTypeBranchProperties& typeProps, f32 age) {\n    branchProps.coreBlockID = typeProps.coreBlockID;\n    branchProps.barkBlockID = typeProps.barkBlockID;\n    branchProps.barkWidth = AGE_LERP_UI16(typeProps.barkWidth);\n    branchProps.coreWidth = AGE_LERP_UI16(typeProps.coreWidth);\n    branchProps.angle = typeProps.angle;\n    branchProps.subBranchAngle = typeProps.subBranchAngle;\n    branchProps.widthFalloff = AGE_LERP_UI16(typeProps.widthFalloff);\n    branchProps.branchChance = AGE_LERP_F32(typeProps.branchChance);\n    branchProps.changeDirChance = AGE_LERP_F32(typeProps.changeDirChance);\n    setLeafProps(branchProps.leafProps, typeProps.leafProps, age);\n    setFruitProps(branchProps.fruitProps, typeProps.fruitProps, age);\n}\n\nvoid FloraGenerator::generateTreeProperties(const NTreeType* type, f32 age, OUT TreeData& tree) {\n    tree.age = age;\n    tree.height = AGE_LERP_UI16(type->height);\n    tree.branchPoints = AGE_LERP_UI16(type->branchPoints);\n    tree.branchStep = AGE_LERP_UI16(type->branchStep);\n    tree.killMult = AGE_LERP_UI16(type->killMult);\n    tree.infRadius = AGE_LERP_F32(type->infRadius);\n    // Set branch volume properties\n    tree.branchVolumes.resize(type->branchVolumes.size());\n    for (size_t i = 0; i < tree.branchVolumes.size(); ++i) {\n        BranchVolumeProperties& bp = tree.branchVolumes[i];\n        const TreeTypeBranchVolumeProperties& tbp = type->branchVolumes[i];\n        bp.height = AGE_LERP_UI16(tbp.height);\n        bp.hRadius = AGE_LERP_UI16(tbp.hRadius);\n        bp.vRadius = AGE_LERP_UI16(tbp.vRadius);\n        bp.points = AGE_LERP_UI16(tbp.points);\n    }\n    // Set trunk properties\n    tree.trunkProps.resize(type->trunkProps.size());\n    // TODO(Ben): no rand!!!\n    tree.currentDir = rand() & 3; // & 3 == % 4\n    for (size_t i = 0; i < tree.trunkProps.size(); ++i) {\n        TreeTrunkProperties& tp = tree.trunkProps[i];\n        const TreeTypeTrunkProperties& ttp = type->trunkProps[i];\n        tp.loc = ttp.loc;\n        tp.coreWidth = AGE_LERP_UI16(ttp.coreWidth);\n        tp.barkWidth = AGE_LERP_UI16(ttp.barkWidth);\n        tp.branchChance = AGE_LERP_F32(ttp.branchChance);\n        tp.coreBlockID = ttp.coreBlockID;\n        tp.barkBlockID = ttp.barkBlockID;\n        tp.interp = ttp.interp;\n        // TODO(Ben): no rand!!!\n        Range<i32> slopeRange;\n        slopeRange.min = rand() % (ttp.slope.min.max - ttp.slope.min.min + 1) + ttp.slope.min.min;\n        slopeRange.max = rand() % (ttp.slope.max.max - ttp.slope.max.min + 1) + ttp.slope.max.min;\n        tp.slope = AGE_LERP_I32(slopeRange);\n        // TODO(Ben): NO RAND\n        tp.changeDirChance = ((f32)rand() / RAND_MAX) * (ttp.changeDirChance.max - ttp.changeDirChance.min) + ttp.changeDirChance.min;\n        setFruitProps(tp.fruitProps, ttp.fruitProps, age);\n        setLeafProps(tp.leafProps, ttp.leafProps, age);\n        setBranchProps(tp.branchProps, ttp.branchProps, age);\n    }\n}\nvoid FloraGenerator::generateFloraProperties(const FloraType* type, f32 age, OUT FloraData& flora) {\n    flora.block = type->block;\n    flora.slope = AGE_LERP_UI16(type->slope);\n    flora.dSlope = AGE_LERP_UI16(type->dSlope);\n    flora.height = AGE_LERP_UI16(type->height);\n    flora.nextFlora = type->nextFlora;\n    switch (type->dir) {\n        case FloraDir::SIDE:\n            flora.dir = rand() % 4; // TODO(Ben): Rand bad!\n            break;\n        case FloraDir::UP:\n            flora.dir = TREE_UP;\n            break;\n        case FloraDir::DOWN:\n            flora.dir = TREE_DOWN;\n            break;\n    }\n}\n#undef AGE_LERP_F32\n#undef AGE_LERP_I32\n#undef AGE_LERP_UI16\n\n#ifdef VORB_OS_WINDOWS\n#pragma endregion\n#endif//VORB_OS_WINDOWS\n\nvoid FloraGenerator::spaceColonization(const f32v3& startPos) {\n    std::vector<f32v3> attractPoints;\n\n    // int numPoints = 500;\n\n    f32 branchStep = (f32)m_treeData.branchStep;\n    f32 infRadius = m_treeData.infRadius;\n    f32 infRadius2 = infRadius * infRadius;\n    f32 killRadius = (f32)(m_treeData.branchStep * m_treeData.killMult);\n    f32 killRadius2 = killRadius * killRadius;\n\n    for (auto& it : m_treeData.branchVolumes) {\n        const f32v3 volCenter(startPos.x, startPos.y + it.height, startPos.z);\n        const f32 hRadius = (f32)it.hRadius;\n        const f32 hDiameter = hRadius * 2.0f;\n        const f32 hRadius2 = hRadius * hRadius;\n        const f32 vRadius = (f32)it.vRadius;\n        const f32 vDiameter = vRadius * 2.0f;\n        const f32 vRadius2 = vRadius * vRadius;\n        // Generate attraction points\n        for (int i = 0; i < it.points; i++) {\n            // TODO(Ben): Worry about double and float casting\n            f32v3 p(m_rGen.genlf() * hDiameter - hRadius, m_rGen.genlf() * vDiameter - vRadius, m_rGen.genlf() * hDiameter - hRadius);\n            // Ellipsoid check\n            f32 d = (p.x * p.x) / hRadius2 + (p.y * p.y) / vRadius2 + (p.z * p.z) / hRadius2;\n           \n            if (d <= 1.0f) {\n                attractPoints.push_back(p + volCenter);\n            }\n        }\n    }\n\n    // Iteratively construct the tree\n    int iter = 0;\n    while (++iter < 10000) {\n        if (attractPoints.size() < 5 || m_scNodes.empty()) return;\n\n        for (int i = (int)attractPoints.size() - 1; i >= 0; --i) {\n            f32 closestDist = FLT_MAX;\n            int closestIndex = -1;\n            // Get closest node and attract it towards attract point\n            for (size_t j = 0; j < m_scNodes.size(); j++) {\n                auto& tn = m_scNodes[j];\n                f32v3 v = attractPoints[i] - m_scRayNodes[tn.rayNode].pos;\n                f32 dist2 = selfDot(v);\n                if (dist2 <= killRadius2) {\n                    attractPoints[i] = attractPoints.back();\n                    attractPoints.pop_back();\n                    closestIndex = -1;\n                    break;\n                } else if (dist2 <= infRadius2 && dist2 < closestDist) {\n                    closestDist = dist2;\n                    closestIndex = j;\n                }\n            }\n            if (closestIndex != -1) {\n                auto& tn = m_scNodes[closestIndex];\n                tn.dir += (attractPoints[i] - m_scRayNodes[tn.rayNode].pos) / closestDist;\n            }\n        }\n\n        // Generate new nodes and erase unneeded ones\n        for (int i = (int)m_scNodes.size() - 1; i >= 0; --i) {\n            SCTreeNode& tn = m_scNodes.at(i);\n            const SCRayNode& n = m_scRayNodes[tn.rayNode];\n            // Self dot?\n            if (tn.dir.x && tn.dir.y && tn.dir.z) {\n                f32v3 pos = n.pos + glm::normalize(tn.dir) * branchStep;\n                tn.dir = f32v3(0.0f);\n                ui32 nextIndex = m_scRayNodes.size();\n                // Change leaf node\n                // TODO(Ben): This can be a vector mebby?\n                auto it = m_scLeafSet.find(tn.rayNode);\n                if (it != m_scLeafSet.end()) m_scLeafSet.erase(it);\n                m_scLeafSet.insert(nextIndex);\n    \n                // Have to make temp copies with emplace_back\n                ui16 trunkPropsIndex = n.trunkPropsIndex;\n                m_scRayNodes.emplace_back(pos, tn.rayNode, trunkPropsIndex);\n                m_scNodes.emplace_back(nextIndex);\n\n            } else {\n                // Remove it since its close to nothing\n     //           m_scNodes[i] = m_scNodes.back();\n     //           m_scNodes.pop_back();\n            }\n        }\n    }\n}\n\n// Priority can not be bigger than 3\ninline void FloraGenerator::tryPlaceNode(std::vector<FloraNode>* nodes, ui8 priority, ui16 blockID, ui16 blockIndex, ui32 chunkOffset) {\n    if (m_currChunkOff != chunkOffset) {\n        m_currChunkOff = chunkOffset;\n        auto it = m_nodeFieldsMap.find(chunkOffset);\n        if (it == m_nodeFieldsMap.end()) {\n            m_currNodeField = m_nodeFields.size();\n            m_nodeFields.emplace_back();\n            m_nodeFieldsMap.insert(std::pair<ui32, int>(chunkOffset, m_currNodeField));\n        } else {\n            m_currNodeField = it->second;\n        }\n    }\n    // For memory compression we pack 4 nodes into each val\n    NodeField& nf = m_nodeFields[m_currNodeField];\n    ui8& val = nf.vals[blockIndex >> 2];\n    ui8 shift = (blockIndex & 0x3) << 1;\n    if ((((val >> shift) & 0x3) < priority)) {\n        nodes->emplace_back(blockID, blockIndex, chunkOffset);\n        // Overwrite priority\n        val &= ~(0x3 << shift);\n        val |= (priority << shift);\n    }\n}\n\n// TODO(Ben): Need to handle different shapes than just round\nvoid FloraGenerator::makeTrunkSlice(ui32 chunkOffset, const TreeTrunkProperties& props) {\n    // This function is so clever\n    int width = (int)(props.coreWidth + props.barkWidth);\n    if (width == 0) return;\n    int innerWidth2 = (int)(props.coreWidth * props.coreWidth);\n    int woodWidth2 = width * width;\n    int woodWidth2m1 = (width - 1) * (width - 1);\n    // Should get layer right outside outer layer\n    int woodWidth2p1 = (width + 1) * (width + 1);\n    // For leaves\n    int leafWidth = 0;\n    ui16 leafBlockID = 0;\n    // Determine outer leaf shape\n    switch (props.leafProps.type) {\n        case TreeLeafType::ROUND:\n            leafWidth = props.leafProps.round.hRadius;\n            leafBlockID = props.leafProps.round.blockID;\n            break;\n        case TreeLeafType::PINE:\n            if (props.leafProps.pine.period == 1) {\n                leafWidth = props.leafProps.pine.oRadius;\n            } else {\n                leafWidth = fastFloor((1.0f - (f32)(m_h % props.leafProps.pine.period) / (props.leafProps.pine.period - 1)) *\n                                      (props.leafProps.pine.oRadius - props.leafProps.pine.iRadius) + 0.5f)\n                                      + props.leafProps.pine.iRadius;\n            }\n            leafBlockID = props.leafProps.pine.blockID;\n            break;\n        default:\n            break;\n    }\n    width += leafWidth;\n    int leafWidth2 = width * width;\n\n    // Get position at back left corner\n    int x = m_center.x;\n    int z = m_center.z;\n    width += 1; // Pad out one so we can check branches on small trees\n    offsetNegative(x, z, X_1, Z_1, chunkOffset, width);\n    x += width;\n    z += width;\n    // Y voxel offset\n    int yOff = m_center.y * CHUNK_LAYER;\n\n    // Distribute branch chance over the circumference of the core\n    f64 branchChance = props.branchChance / (M_2_PI * (f64)(props.coreWidth + props.barkWidth));\n\n    for (int dz = -width; dz <= width; ++dz) {\n        for (int dx = -width; dx <= width; ++dx) {\n            int dist2 = dx * dx + dz * dz;\n            if (dist2 < woodWidth2) { // Wood block\n                // Get position\n                i32v2 pos(x + dx, z + dz);\n                ui32 chunkOff = chunkOffset;\n                addChunkOffset(pos, chunkOff);\n                ui16 blockIndex = (ui16)(pos.x + yOff + pos.y * CHUNK_WIDTH);\n                if (dist2 > woodWidth2m1) {\n                    if (m_rGen.gen() % OUTER_SKIP_MOD) {\n                        if (dist2 < innerWidth2) {\n                            tryPlaceNode(m_wNodes, 3, props.coreBlockID, blockIndex, chunkOff);\n                        } else {\n                            tryPlaceNode(m_wNodes, 3, props.barkBlockID, blockIndex, chunkOff);\n                        }\n                    }\n                } else {\n                    if (dist2 < innerWidth2) {\n                        tryPlaceNode(m_wNodes, 3, props.coreBlockID, blockIndex, chunkOff);\n                    } else {\n                        tryPlaceNode(m_wNodes, 3, props.barkBlockID, blockIndex, chunkOff);\n                    }\n                }\n            } else if (dist2 < woodWidth2p1) { // Fruit and branching\n                // Get position\n                i32v2 pos(x + dx, z + dz);\n                ui32 chunkOff = chunkOffset;\n                addChunkOffset(pos, chunkOff);\n                ui16 blockIndex = (ui16)(pos.x + yOff + pos.y * CHUNK_WIDTH);\n\n                if (m_rGen.genlf() < branchChance) {\n                    // TODO(Ben): If check\n                    if (!m_hasStoredTrunkProps) {\n                        m_scTrunkProps.push_back(props);\n                        m_hasStoredTrunkProps = true;\n                    }\n                    m_branchesToGenerate.emplace_back(blockIndex, chunkOff, dx, dz, m_scTrunkProps.size() - 1);\n                } else if (leafWidth && leafBlockID) {\n                    tryPlaceNode(m_fNodes, 1, leafBlockID, blockIndex, chunkOff);\n                }\n            } else if (dist2 < leafWidth2 && leafBlockID) { // Leaves\n                // Get position\n                i32v2 pos(x + dx, z + dz);\n                ui32 chunkOff = chunkOffset;\n                addChunkOffset(pos, chunkOff);\n                ui16 blockIndex = (ui16)(pos.x + yOff + pos.y * CHUNK_WIDTH);\n                tryPlaceNode(m_fNodes, 1, leafBlockID, blockIndex, chunkOff);\n            }\n        }\n    }\n}\n\ninline f32 fastFloorf(f32 x) {\n    return FastConversion<f32, f32>::floor(x);\n}\ninline f32 fastCeilf(f32 x) {\n    return FastConversion<f32, f32>::ceiling(x);\n}\n\nvoid FloraGenerator::generateBranch(ui32 chunkOffset, int x, int y, int z, f32 length, f32 width, f32 endWidth, f32v3 dir, bool makeLeaves, bool hasParent, const TreeBranchProperties& props) {\n    \n    if (width < 1.0f) return;\n    int startX = x;\n    int startY = y;\n    int startZ = z;\n    ui32 startChunkOffset = chunkOffset;\n\n    f32v3 start(0.0f);\n    f32v3 end = dir * length;\n\n    // Compute bounding box\n    f32 minX = 0.0f, maxX = 0.0f;\n    f32 minY = 0.0f, maxY = 0.0f;\n    f32 minZ = 0.0f, maxZ = 0.0f;\n\n    if (end.x < minX) minX = end.x;\n    if (end.x > maxX) maxX = end.x;\n    if (end.y < minY) minY = end.y;\n    if (end.y > maxY) maxY = end.y;\n    if (end.z < minZ) minZ = end.z;\n    if (end.z > maxZ) maxZ = end.z;\n\n    // Pad the box by width + 1\n    f32 wp1 = glm::max(width, endWidth) + 1;\n    minX -= wp1;\n    maxX += wp1;\n    minY -= wp1;\n    maxY += wp1;\n    minZ -= wp1;\n    maxZ += wp1;\n\n    // Round down to voxel position\n    i32v3 min(fastFloor(minX), fastFloor(minY), fastFloor(minZ));\n    i32v3 max(fastFloor(maxX), fastFloor(maxY), fastFloor(maxZ));\n\n    // Offset to back corner\n    offsetByPos(x, y, z, chunkOffset, min);\n\n    // Make start and end relative to min\n    start -= min;\n    end -= min;\n\n    const f32v3 ray = (end - start);\n    const f32 l2 = selfDot(ray);\n    // Iterate the volume and check points against line segment\n    for (int i = 0; i < max.y - min.y; i++) {\n        for (int j = 0; j < max.z - min.z; j++) {\n            for (int k = 0; k < max.x - min.x; k++) {\n                // http://stackoverflow.com/a/1501725/3346893\n                const f32v3 vec(k, i, j);\n                const f32v3 v2 = vec - start;\n                const f32 t = glm::dot(v2, ray) / l2;\n\n                // Compute distance2\n                f32 dist2;\n                f32 innerWidth;\n                bool canFruit = false;\n                if (t < 0.0) {\n                    dist2 = selfDot(v2);\n                    innerWidth = width;\n                } else if (t > 1.0) {\n                    // Parent will fill these nodes in.\n                    if (hasParent) continue;\n                    dist2 = selfDot(vec - end);\n                    innerWidth = endWidth;\n                } else {\n                    const f32v3 projection = start + t * ray;\n                    dist2 = selfDot(vec - projection);\n                    // Lerp the branch width\n                    innerWidth = lerp(width, endWidth, t);\n                    canFruit = true;\n                }\n                    \n                f32 width2 = innerWidth * innerWidth;\n                f32 width2p1 = (innerWidth + 1) * (innerWidth + 1);\n                f32 width2m1 = (innerWidth - 1) * (innerWidth - 1);\n                if (width2m1 == 0) width2m1 = FLT_MAX;\n      \n                if (dist2 < width2) {\n                    i32v3 pos(x + k, y + i, z + j);\n                    ui32 chunkOff = chunkOffset;\n                    addChunkOffset(pos, chunkOff);\n                    ui16 newIndex = (ui16)(pos.x + pos.y * CHUNK_LAYER + pos.z * CHUNK_WIDTH);\n                    if (dist2 > width2m1 + 1) {\n                        if (m_rGen.gen() % OUTER_SKIP_MOD) tryPlaceNode(m_wNodes, 3, props.coreBlockID, newIndex, chunkOff);\n                    } else {\n                        tryPlaceNode(m_wNodes, 3, props.coreBlockID, newIndex, chunkOff);\n                    }\n                } else if (canFruit && dist2 < width2p1 && props.fruitProps.flora != FLORA_ID_NONE) {\n                    // Distribute fruit chance over the circumference of the branch\n                    f64 fruitChance = props.fruitProps.chance / (M_2_PI * (f64)(innerWidth));\n                    if (m_rGen.genlf() <= fruitChance) {\n                        i32v3 pos(x + k, y + i, z + j);\n                        ui32 chunkOff = chunkOffset;\n                        addChunkOffset(pos, chunkOff);\n                        ui16 newIndex = (ui16)(pos.x + pos.y * CHUNK_LAYER + pos.z * CHUNK_WIDTH);\n                        generateFlora(&m_genData->flora.at(props.fruitProps.flora), 1.0f, *m_fNodes, *m_wNodes, chunkOff, newIndex);\n                    }\n                }\n            }\n        }\n    }\n\n    if (makeLeaves) {\n        ui16 newIndex = (ui16)(startX + startY * CHUNK_LAYER + startZ * CHUNK_WIDTH);\n        m_leavesToPlace.emplace_back(newIndex, startChunkOffset, &props.leafProps);\n    }  \n}\n\nvoid FloraGenerator::generateSCBranches() {\n\n    // Check for performance issues.\n    if (m_scRayNodes.size() > 4000) {\n        if (m_scRayNodes.size() > 32768) {\n            printf(\"ERROR: Tree has %zuray nodes but limited to 32768\\n\", m_scRayNodes.size());\n            m_scRayNodes.clear();\n        } else {\n            printf(\"Performance warning: tree has %zu ray nodes\\n\", m_scRayNodes.size());\n        }\n    }\n\n    std::vector <ui32> lNodesToAdd;\n    // Set widths and sub branches\n    for (auto& l : m_scLeafSet) {\n        ui32 i = l;\n        while (true) {\n            SCRayNode& a = m_scRayNodes[i];\n            a.wasVisited = 1; // a helpful flag\n            i = a.parent;\n            if (i == SC_NO_PARENT) break;\n            SCRayNode& b = m_scRayNodes[i];\n            TreeBranchProperties& tbp = m_scTrunkProps[b.trunkPropsIndex].branchProps;\n            f32 nw = a.width + tbp.widthFalloff * m_treeData.branchStep;\n\n            if (b.wasVisited) {\n                if (b.width >= nw) break;\n                b.width = nw;\n                if (b.width > tbp.barkWidth + tbp.coreWidth) {\n                    b.width = (f32)(tbp.barkWidth + tbp.coreWidth);\n                }\n            } else {\n                b.width = nw;\n                if (b.width > tbp.barkWidth + tbp.coreWidth) {\n                    b.width = (f32)(tbp.barkWidth + tbp.coreWidth);\n                }\n                \n                // Calculate sub branching\n                if (tbp.branchChance > 0.0f) {\n                    f32v3 dir = glm::normalize(b.pos - a.pos);\n                    f32 length = glm::length(dir);\n                    dir /= length;\n                    for (f32 v = 0.0f; v < length; v += 1.0f) {\n                        if (m_rGen.genlf() < tbp.branchChance) {\n                            f32 width = lerp(a.width, b.width, v / length);\n                            // TODO(Ben): Width falloff aint working right?\n                            f32 sLength = width / tbp.widthFalloff;\n                            // Determine float position\n                            f32v3 pos = a.pos + dir * v;\n                            \n                            // Add root\n                            ui16 parent = m_scRayNodes.size();\n                            ui16 tpIndex = a.trunkPropsIndex;\n                            // a and b are invalidated with emplace_back\n                            m_scRayNodes.emplace_back(pos, SC_NO_PARENT, tpIndex);\n                            m_scRayNodes.back().width = width;\n                            // Determine chain length\n                            int numSegments = (int)(sLength * tbp.changeDirChance);\n                            numSegments++;\n                            sLength /= numSegments;\n                            // Create branch chain\n                            int j = 0;\n                            f32v3 nDir = dir;\n                            while (true) {\n                                // Get new dir\n                                newDirFromAngle(nDir, tbp.subBranchAngle.min, tbp.subBranchAngle.max);\n                                pos += nDir * sLength;\n                                m_scRayNodes.emplace_back(pos, parent, tpIndex);\n                                m_scRayNodes.back().width = width * ((f32)(numSegments - j - 1) / numSegments) + 1.0f;\n                                // Check end condition\n                                if (++j == numSegments) break;\n                                parent = m_scRayNodes.size() - 1;\n                                if (parent >= 32767) {\n                                    break;\n                                }\n                            }\n                            // Last node is leaf\n                            lNodesToAdd.push_back(m_scRayNodes.size() - 1);\n                        }\n                    }\n                }\n            }\n        }\n    }\n    for (auto& i : lNodesToAdd) {\n        m_scLeafSet.insert(i);\n    }\n\n    // Make branches\n    // int a = 0;\n    for (auto& l : m_scLeafSet) {\n        ui32 i = l;\n        bool hasLeaves = true;\n        while (true) {\n            SCRayNode& a = m_scRayNodes[i];\n            i = a.parent;\n            if (i == SC_NO_PARENT) break;\n            a.parent = SC_NO_PARENT;\n            SCRayNode& b = m_scRayNodes[i];\n\n            f32v3 dir = b.pos - a.pos;\n            f32 length = glm::length(dir);\n            dir /= length;\n           \n            i32v3 iPosA(a.pos);\n            int x = 0;\n            int y = 0;\n            int z = 0;\n            ui32 chunkOffset = NO_CHUNK_OFFSET;\n            offsetByPos(x, y, z, chunkOffset, iPosA);\n            generateBranch(chunkOffset, x, y, z, length, a.width, b.width, dir, hasLeaves,\n                           b.parent != SC_NO_PARENT, m_scTrunkProps[b.trunkPropsIndex].branchProps);\n            hasLeaves = false;\n        }\n    }\n}\n\ninline void FloraGenerator::generateLeaves(ui32 chunkOffset, int x, int y, int z, const TreeLeafProperties& props) {\n    // TODO(Ben): OTHER TYPES\n    switch (props.type) {\n        case TreeLeafType::ROUND:\n            if (props.round.vRadius == props.round.hRadius) {\n                generateRoundLeaves(chunkOffset, x, y, z, props);\n            } else {\n                generateEllipseLeaves(chunkOffset, x, y, z, props);\n            }\n            break;\n        case TreeLeafType::MUSHROOM:\n            generateMushroomCap(chunkOffset, x, y, z, props);\n            break;\n        default:\n            // Pine leaves cant generate on branches\n            break;\n    }\n}\n\n// Faster than ellipse for when the leaves are perfectly round\nvoid FloraGenerator::generateRoundLeaves(ui32 chunkOffset, int x, int y, int z, const TreeLeafProperties& props) {\n    int radius = (int)(props.round.hRadius);\n    int radius2 = radius * radius;\n    int radius2m1 = (radius - 1) * (radius - 1);\n    if (radius2m1 == 0) radius2m1 = INT_MAX;\n    // Get position at back left corner\n    offsetNegative(x, y, z, chunkOffset, radius - 1);\n\n    x += radius;\n    y += radius;\n    z += radius;\n    for (int dy = -radius; dy <= radius; ++dy) {\n        for (int dz = -radius; dz <= radius; ++dz) {\n            for (int dx = -radius; dx <= radius; ++dx) {\n                int dist2 = dx * dx + dy * dy + dz * dz;\n                if (dist2 < radius2) {\n                    i32v3 pos(x + dx, y + dy, z + dz);\n                    ui32 chunkOff = chunkOffset;\n                    addChunkOffset(pos, chunkOff);\n                    ui16 blockIndex = (ui16)(pos.x + pos.y * CHUNK_LAYER + pos.z * CHUNK_WIDTH);\n                    if (dist2 > radius2m1) {\n                        if (m_rGen.gen() % OUTER_SKIP_MOD) tryPlaceNode(m_fNodes, 1, props.round.blockID, blockIndex, chunkOff);\n                    } else {\n                        tryPlaceNode(m_fNodes, 1, props.round.blockID, blockIndex, chunkOff);\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid FloraGenerator::generateEllipseLeaves(ui32 chunkOffset, int x, int y, int z, const TreeLeafProperties& props) {\n    // Offset to bottom\n    int offset = props.round.vRadius;\n    // int tmp = y;\n    offsetNegative(y, Y_1, chunkOffset, offset);\n    // Use equation of ellipse\n    f32 fOffset = (f32)offset;\n    f32 a = (f32)props.round.hRadius;\n    f32 b = (f32)(props.round.vRadius * props.round.vRadius);\n    for (f32 i = 0.0f; i < fOffset * 2.0f + 1.0f; i += 1.0f) {\n        f32 ey = fOffset - i;\n        f32 radius = sqrtf(1.0f - (ey * ey) / b) * a;\n        f32 radius2 = radius * radius;\n        f32 radius2m1 = (radius - 1) * (radius - 1);\n        if (radius2m1 == 0) radius2m1 = FLT_MAX;\n        const int yOff = y * CHUNK_LAYER;\n        // Offset to back left\n        int offset = fastFloor(radius);\n        int x2 = x;\n        int z2 = z;\n        ui32 innerChunkOffset = chunkOffset;\n        offsetNegative(x2, z2, X_1, Z_1, innerChunkOffset, offset);\n        x2 += offset;\n        z2 += offset;\n        // Make the layer\n        for (int dz = -offset; dz <= offset; ++dz) {\n            for (int dx = -offset; dx <= offset; ++dx) {\n                int dist2 = dx * dx + dz * dz;\n                if ((f32)dist2 < radius2) {\n                    i32v2 pos(x2 + dx, z2 + dz);\n                    ui32 chunkOff = innerChunkOffset;\n                    addChunkOffset(pos, chunkOff);\n                    ui16 blockIndex = (ui16)(pos.x + yOff + pos.y * CHUNK_WIDTH);\n                    if (dist2 > radius2m1) {\n                        if (m_rGen.gen() % OUTER_SKIP_MOD) tryPlaceNode(m_fNodes, 1, props.round.blockID, blockIndex, chunkOff);\n                    } else {\n                        tryPlaceNode(m_fNodes, 1, props.round.blockID, blockIndex, chunkOff);\n                    }\n                }\n            }\n        }\n        \n        offsetPositive(y, Y_1, chunkOffset, 1);\n    }\n}\n\nvoid FloraGenerator::generateMushroomCap(ui32 chunkOffset, int x, int y, int z, const TreeLeafProperties& props) {\n    \n    int startY = y;\n    ui32 startChunkOffset = chunkOffset;\n    if (props.mushroom.tvRadius) { // Top half\n        // Offset to middle of cap\n        int offset = props.mushroom.tvRadius;\n        offsetNegative(y, Y_1, chunkOffset, offset);\n        // Parameters\n        f32 fOffset = (f32)offset;\n        f32 a = (f32)props.mushroom.thRadius;\n        f32 b = (f32)(props.mushroom.tvRadius * props.mushroom.tvRadius);\n        f32 thickness = (f32)(props.mushroom.capWidth + props.mushroom.gillWidth);\n\n        // Top half\n        for (f32 i = 0.0f; i < fOffset + 1.0f; i += 1.0f) {\n            // Equation of ellipse\n            f32 radius = sqrtf(1.0f - (i * i) / b) * a;\n            f32 capRadius2 = radius - props.mushroom.capWidth;\n            capRadius2 = capRadius2 * capRadius2;\n            f32 innerRadius2 = radius - thickness;\n            if (innerRadius2 < 0.0f) {\n                innerRadius2 = 0.0f;\n            } else {\n                innerRadius2 = innerRadius2 * innerRadius2;\n            }\n            f32 radius2 = radius * radius;\n            const int yOff = y * CHUNK_LAYER;\n            // Offset to back left\n            int innerOffset = fastFloor(radius);\n            int x2 = x;\n            int z2 = z;\n            ui32 innerChunkOffset = chunkOffset;\n            offsetNegative(x2, z2, X_1, Z_1, innerChunkOffset, innerOffset);\n            x2 += innerOffset;\n            z2 += innerOffset;\n            // Make the layer\n            for (int dz = -innerOffset; dz <= innerOffset; ++dz) {\n                for (int dx = -innerOffset; dx <= innerOffset; ++dx) {\n                    f32 dist2 = (f32)(dx * dx + dz * dz);\n                    if (dist2 < radius2 && dist2 > innerRadius2) {\n                        i32v2 pos(x2 + dx, z2 + dz);\n                        ui32 chunkOff = innerChunkOffset;\n                        addChunkOffset(pos, chunkOff);\n                        ui16 blockIndex = (ui16)(pos.x + yOff + pos.y * CHUNK_WIDTH);\n                        if (dist2 >= capRadius2) {\n                            tryPlaceNode(m_fNodes, 1, props.mushroom.capBlockID, blockIndex, chunkOff);\n                        } else {\n                            tryPlaceNode(m_fNodes, 1, props.mushroom.gillBlockID, blockIndex, chunkOff);\n                        }\n                    }\n                }\n            }\n            offsetPositive(y, Y_1, chunkOffset, 1);\n        }\n    }\n\n    if (props.mushroom.bLength && props.mushroom.bvRadius) { // Bottom half\n        y = startY;\n        chunkOffset = startChunkOffset;\n        // Offset to bottom of cap and skip layers as needed\n        int skipped = props.mushroom.bvRadius - props.mushroom.bLength;\n        if (skipped < 0) return;\n        int offset = props.mushroom.bvRadius - skipped;\n        offsetNegative(y, Y_1, chunkOffset, offset + props.mushroom.tvRadius + 1);\n        // Parameters\n        f32 fOffset = (f32)props.mushroom.bvRadius;\n        // f32 a = (f32)props.mushroom.bhRadius;\n        f32 b = (f32)(props.mushroom.bvRadius * props.mushroom.bvRadius);\n        f32 thickness = (f32)(props.mushroom.capWidth + props.mushroom.gillWidth);\n\n        // Top half\n        f32 end = fOffset + 1.0f;\n        f32 fSkipped = (f32)skipped;\n        for (f32 i = fSkipped; i < end; i += 1.0f) {\n            // Get lerp factor\n            f32 l = (i - fSkipped) / (end - fSkipped);\n            smoothInterpFactor(l, props.mushroom.interp);\n            // Lerp the a\n            f32 a = ((f32)props.mushroom.thRadius - (f32)props.mushroom.bhRadius) * l + props.mushroom.bhRadius;\n            // Equation of ellipse\n            f32 ey = fOffset - i;\n            f32 radius = sqrtf(1.0f - (ey * ey) / b) * a;\n            f32 capRadius2 = radius - props.mushroom.capWidth;\n            capRadius2 = capRadius2 * capRadius2;\n            f32 innerRadius2 = radius - thickness;\n            if (innerRadius2 < 0.0f) {\n                innerRadius2 = 0.0f;\n            } else {\n                innerRadius2 = innerRadius2 * innerRadius2;\n            }\n            f32 radius2 = radius * radius;\n            const int yOff = y * CHUNK_LAYER;\n            // Offset to back left\n            int innerOffset = fastFloor(radius);\n            int x2 = x;\n            int z2 = z;\n            ui32 innerChunkOffset = chunkOffset;\n            offsetNegative(x2, z2, X_1, Z_1, innerChunkOffset, innerOffset);\n            x2 += innerOffset;\n            z2 += innerOffset;\n            // Make the layer\n            for (int dz = -innerOffset; dz <= innerOffset; ++dz) {\n                for (int dx = -innerOffset; dx <= innerOffset; ++dx) {\n                    f32 dist2 = (f32)(dx * dx + dz * dz);\n                    if (dist2 < radius2 && dist2 > innerRadius2) {\n                        i32v2 pos(x2 + dx, z2 + dz);\n                        ui32 chunkOff = innerChunkOffset;\n                        addChunkOffset(pos, chunkOff);\n                        ui16 blockIndex = (ui16)(pos.x + yOff + pos.y * CHUNK_WIDTH);\n                        if (dist2 >= capRadius2) {\n                            tryPlaceNode(m_fNodes, 1, props.mushroom.capBlockID, blockIndex, chunkOff);\n                        } else {\n                            tryPlaceNode(m_fNodes, 1, props.mushroom.gillBlockID, blockIndex, chunkOff);\n                        }\n                    }\n                }\n            }\n            offsetPositive(y, Y_1, chunkOffset, 1);\n        }\n    }\n}\n\ninline void FloraGenerator::newDirFromAngle(f32v3& dir, f32 minAngle, f32 maxAngle) {\n    f32 angle = (f32)(m_rGen.genlf() * (maxAngle - minAngle) + minAngle);\n    f32v3 relDir(0.0f, cos(angle), sin(angle));\n    relDir = glm::angleAxis((f32)(m_rGen.genlf() * 360.0), f32v3(0.0f, 1.0f, 0.0f)) * relDir;\n    // Transform relDir relative to dir with change of basis matrix\n    f32v3 nz = glm::cross(dir, f32v3(0.0f, 1.0f, 0.0f));\n    f32v3 nx = glm::cross(dir, nz);\n    f32m3 trans(nx, dir, nz);\n    dir = trans * relDir;\n}"
  },
  {
    "path": "SoA/FloraGenerator.h",
    "content": "///\n/// NFloraGenerator.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 15 Jul 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Generates flora and trees\n///\n\n#pragma once\n\n#ifndef NFloraGenerator_h__\n#define NFloraGenerator_h__\n\n#include \"Flora.h\"\n#include \"Chunk.h\"\n#include \"soaUtils.h\"\n\n// 0111111111 0111111111 0111111111 = 0x1FF7FDFF\n#define NO_CHUNK_OFFSET 0x1FF7FDFF\n\nstruct PlanetGenData;\n\n// Will not work for chunks > 32^3\nstruct FloraNode {\n    FloraNode(ui16 blockID, ui16 blockIndex, ui32 chunkOffset) :\n        blockID(blockID), blockIndex(blockIndex), chunkOffset(chunkOffset) {\n    };\n    ui16 blockID;\n    ui16 blockIndex;\n    // TODO(Ben): ui32 instead for massive trees? Use leftover bits for Y?\n    ui32 chunkOffset; ///< Packed 00 XXXXXXXXXX YYYYYYYYYY ZZZZZZZZZZ for positional offset. 00111 == 0\n};\n\n#define SC_NO_PARENT 0x7FFFu\n\nstruct SCRayNode {\n    SCRayNode(const f32v3& pos, ui16 parent, ui16 trunkPropsIndex) :\n        pos(pos), trunkPropsIndex(trunkPropsIndex), wasVisited(0), parent(parent){};\n    f32v3 pos;\n    ui16 trunkPropsIndex;\n    ui16 wasVisited;\n    ui16 parent;\n    f32 width = 1.0f; \n};\n\nstruct SCTreeNode {\n    SCTreeNode(ui16 rayNode) :\n        rayNode(rayNode), dir(0.0f) {};\n    ui16 rayNode;\n    f32v3 dir;\n};\n\nstruct NodeField {\n    NodeField() {\n        memset(vals, 0, sizeof(vals));\n    }\n    // Each node is 2 bits\n    ui8 vals[CHUNK_SIZE / 4];\n};\n\n// Defer leaf placement to prevent node overlap\nstruct LeavesToPlace {\n    LeavesToPlace(ui16 blockIndex, ui32 chunkOffset, const TreeLeafProperties* leafProps) :\n    blockIndex(blockIndex), chunkOffset(chunkOffset), leafProps(leafProps) { }\n    ui16 blockIndex;\n    ui32 chunkOffset;\n    const TreeLeafProperties* leafProps;\n};\n\n// Defer manual branch placement so it doesn't conflict with SC\nstruct BranchToGenerate {\n    BranchToGenerate(ui16 blockIndex, ui32 chunkOffset, i32 dx, i32 dz, ui16 trunkPropsIndex) :\n        blockIndex(blockIndex), trunkPropsIndex(trunkPropsIndex), chunkOffset(chunkOffset), dx(dx), dz(dz) {\n    }\n    ui16 blockIndex;\n    ui16 trunkPropsIndex;\n    ui32 chunkOffset;\n    i32 dx;\n    i32 dz;\n};\n\n// TODO(Ben): Add comments\nclass FloraGenerator {\npublic:\n    /// @brief Generates flora for a chunk using its QueuedFlora.\n    /// @param chunk: Chunk who's flora should be generated.\n    /// @param gridData: The heightmap to use\n    /// @param fNodes: Returned low priority nodes, for flora and leaves.\n    /// @param wNodes: Returned high priority nodes, for tree \"wood\".\n    void generateChunkFlora(const Chunk* chunk, const PlanetHeightData* heightData, OUT std::vector<FloraNode>& fNodes, OUT std::vector<FloraNode>& wNodes);\n    /// Generates standalone tree.\n    void generateTree(const NTreeType* type, f32 age, OUT std::vector<FloraNode>& fNodes, OUT std::vector<FloraNode>& wNodes, const PlanetGenData* genData, ui32 chunkOffset = NO_CHUNK_OFFSET, ui16 blockIndex = 0);\n    /// Generates standalone flora.\n    void generateFlora(const FloraType* type, f32 age, OUT std::vector<FloraNode>& fNodes, OUT std::vector<FloraNode>& wNodes, ui32 chunkOffset = NO_CHUNK_OFFSET, ui16 blockIndex = 0);\n    /// Generates a specific tree's properties\n    static void generateTreeProperties(const NTreeType* type, f32 age, OUT TreeData& tree);\n    static void generateFloraProperties(const FloraType* type, f32 age, OUT FloraData& flora);\n\n    void spaceColonization(const f32v3& startPos);\n\n    static inline int getChunkXOffset(ui32 chunkOffset) {\n        return (int)((chunkOffset >> 20) & 0x3FF) - 0x1FF;\n    }\n    static inline int getChunkYOffset(ui32 chunkOffset) {\n        return (int)((chunkOffset >> 10) & 0x3FF) - 0x1FF;\n    }\n    static inline int getChunkZOffset(ui32 chunkOffset) {\n        return (int)(chunkOffset & 0x3FF) - 0x1FF;\n    }\nprivate:\n    enum TreeDir {\n        TREE_LEFT = 0, TREE_BACK, TREE_RIGHT, TREE_FRONT, TREE_UP, TREE_DOWN, TREE_NO_DIR\n    };\n\n    void tryPlaceNode(std::vector<FloraNode>* nodes, ui8 priority, ui16 blockID, ui16 blockIndex, ui32 chunkOffset);\n    void makeTrunkSlice(ui32 chunkOffset, const TreeTrunkProperties& props);\n    void generateBranch(ui32 chunkOffset, int x, int y, int z, f32 length, f32 width, f32 endWidth, f32v3 dir, bool makeLeaves, bool hasParent, const TreeBranchProperties& props);\n    void generateSCBranches();\n    void generateLeaves(ui32 chunkOffset, int x, int y, int z, const TreeLeafProperties& props);\n    void generateRoundLeaves(ui32 chunkOffset, int x, int y, int z, const TreeLeafProperties& props);\n    void generateEllipseLeaves(ui32 chunkOffset, int x, int y, int z, const TreeLeafProperties& props);\n    void generateMushroomCap(ui32 chunkOffset, int x, int y, int z, const TreeLeafProperties& props);\n    void newDirFromAngle(f32v3& dir, f32 minAngle, f32 maxAngle);\n\n    std::set<ui32> m_scLeafSet;\n    std::unordered_map<ui32, ui32> m_nodeFieldsMap;\n    std::vector<NodeField> m_nodeFields;\n    std::vector<SCRayNode> m_scRayNodes;\n    std::vector<SCTreeNode> m_scNodes;\n    std::vector<LeavesToPlace> m_leavesToPlace;\n    std::vector<BranchToGenerate> m_branchesToGenerate;\n    std::vector<TreeTrunkProperties> m_scTrunkProps; ///< Stores branch properties for nodes\n    std::vector<FloraNode>* m_fNodes;\n    std::vector<FloraNode>* m_wNodes;\n    TreeData m_treeData;\n//    FloraData m_floraData;\n    i32v3 m_center;\n    ui32 m_h; ///< Current height along the tree\n    FastRandGenerator m_rGen;\n    ui32 m_currChunkOff;\n    ui32 m_currNodeField;\n    const PlanetGenData* m_genData;\n    bool m_hasStoredTrunkProps;\n};\n\n#endif // NFloraGenerator_h__\n"
  },
  {
    "path": "SoA/FragFile.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FragFile.h\"\n\n// Fragmentation Seeking Information\nclass FragBlockHeader {\npublic:\n    // Path ID\n    i32 id;\n    // The Size Of The Current Block\n    i32 sizeBlock;\n    // Offset Into The File Relative To The End Of Data Block\n    i32 offset;\n};\n// A Header For Each Data Path\nclass FragHeader {\npublic:\n    // The Total Size Of The Path\n    i32 totalSize;\n    // First Data Block\n    FragBlockHeader firstBlock;\n    // Last Data Block\n    FragBlockHeader lastBlock;\n};\n\nFragFile::FragFile(i32 numPaths, const cString path, bool isReadonly) :\n_file(nullptr),\n_curPath(0),\n_numDataPaths(numPaths),\n_headerSizeInBytes(_numDataPaths * sizeof(FragHeader)),\n_headers(nullptr) {\n    bool isSuccess = isReadonly ? openReadonlyFile(path) : openWritingFile(path);\n    if (!isSuccess) {\n        _file = nullptr;\n#ifdef DEBUG\n        printf(\"Error Attempting To Open Fragmented File:\\n%s\\n\", path);\n#endif // DEBUG\n    }\n}\nFragFile::~FragFile() {\n    close();\n}\n\nvoid FragFile::setDataPath(i32 p) {\n    if (p < 0 || p >= _numDataPaths) {\n#ifdef DEBUG\n        printf(\"Attempting To Access Invalid Path\\n\");\n#endif // DEBUG\n        exit(-1);\n    }\n    _curPath = p;\n}\n\ni32 FragFile::getDataPathSize() const {\n    return _headers[_curPath].totalSize;\n}\n\nvoid FragFile::read(void* buf) {\n    ui8* data = (ui8*)buf;\n\n    // Get Data Block Information\n    i32 bytesLeft = getDataPathSize();\n    FragBlockHeader header = _headers[_curPath].firstBlock;\n\n    // Move To The First Block\n    fseek(_file, header.offset + _headerSizeInBytes, SEEK_SET);\n\n    while (bytesLeft > 0) {\n        // Read The Header For The Block\n        fread(&header, sizeof(FragBlockHeader), 1, _file);\n\n        // Read The Data Of The Current Block\n        fread(data, 1, header.sizeBlock, _file);\n        bytesLeft -= header.sizeBlock;\n\n        // Move Pointers\n        data += header.sizeBlock;\n\n        // Seek The Next Block\n        if (bytesLeft > 0) fseek(_file, header.offset, SEEK_CUR);\n    }\n}\n\nvoid FragFile::append(void* data, i32 sizeInBytes) {\n    // Move To The End Of The File\n    fseek(_file, 0, SEEK_END);\n    i32 initialSize = getDataPathSize();\n    _headers[_curPath].totalSize += sizeInBytes;\n\n    // Create The Header\n    FragBlockHeader header = {};\n    header.id = _curPath;\n    header.sizeBlock = sizeInBytes;\n\n    // Store Our Position\n    i32 fpos = ftell(_file);\n\n    // Write The Fragmented Data Block\n    fwrite(&header, sizeof(FragBlockHeader), 1, _file);\n    fwrite(data, 1, sizeInBytes, _file);\n\n    // Allow Seek Time\n    fseek(_file, _curPath * sizeof(FragHeader), SEEK_SET);\n\n    // Exchange Info About Last Known Block\n    i32 otherPos = _headers[_curPath].lastBlock.offset;\n    _headers[_curPath].lastBlock.offset = fpos - _headerSizeInBytes;\n    i32 otherSize = _headers[_curPath].lastBlock.sizeBlock;\n    _headers[_curPath].lastBlock.sizeBlock = sizeInBytes;\n\n    // Check If We've Written Anything Before\n    if (initialSize == 0) {\n        _headers[_curPath].firstBlock = _headers[_curPath].lastBlock;\n    }\n\n    // Write The New Header\n    fwrite(&_headers[_curPath], sizeof(FragHeader), 1, _file);\n\n    if (initialSize != 0) {\n        // Go To The Previous Last Block\n        fseek(_file, otherPos + _headerSizeInBytes, SEEK_SET);\n\n        // Reset Offset Information\n        header.offset = fpos - otherPos;\n        header.offset -= otherSize + sizeof(FragBlockHeader);\n        header.offset -= _headerSizeInBytes;\n\n        // Overwrite\n        header.sizeBlock = otherSize;\n        fwrite(&header, sizeof(FragBlockHeader), 1, _file);\n    }\n}\nvoid FragFile::overwrite(void* data VORB_UNUSED, i32 fileDataOffset VORB_UNUSED) {\n    // TODO: Implement\n}\n\nvoid FragFile::defragment(const cString tmpFileName VORB_UNUSED) {\n    // TODO: Implement\n}\n\nvoid FragFile::flush() {\n    fflush(_file);\n}\nvoid FragFile::close() {\n    if (_file) {\n        flush();\n        fclose(_file);\n        _file = nullptr;\n    }\n    if (_headers) {\n        delete[] _headers;\n        _headers = nullptr;\n    }\n}\n\nbool FragFile::openReadonlyFile(const cString path) {\n    // Check For A Path\n    if (!path) return false;\n\n    // Attempt To Open The File\n    _file = fopen(path, \"rb\");\n    if (_file == nullptr) return false;\n\n    // Read The Headers (They Must Be There)\n    fseek(_file, 0, SEEK_END);\n    i32 len = ftell(_file);\n    fseek(_file, 0, SEEK_SET);\n    len -= ftell(_file);\n\n    if (len < _headerSizeInBytes) {\n        // The Headers Must Have Not Been Written\n        fclose(_file);\n        return false;\n    } else {\n        // Read The Headers\n        _headers = new FragHeader[_numDataPaths];\n        fread(_headers, sizeof(FragHeader), _numDataPaths, _file);\n        return true;\n    }\n}\nbool FragFile::openWritingFile(const cString path) {\n    // Check For A Path\n    if (!path) return false;\n\n    // Attempt To Open The File\n    _file = fopen(path, \"wb+\");\n    if (_file == nullptr) return false;\n\n    // Try To Read The Headers\n    fseek(_file, 0, SEEK_END);\n    i32 len = ftell(_file);\n    fseek(_file, 0, SEEK_SET);\n    len -= ftell(_file);\n\n    if (len < _headerSizeInBytes) {\n        // Write New Headers\n        _headers = new FragHeader[_numDataPaths]();\n        for (i32 i = 0; i < _numDataPaths; i++) {\n            _headers[i].firstBlock.id = i;\n            _headers[i].firstBlock.id = i;\n        }\n        fwrite(_headers, sizeof(FragHeader), _numDataPaths, _file);\n    } else {\n        // Read The Headers\n        _headers = new FragHeader[_numDataPaths];\n        fread(_headers, sizeof(FragHeader), _numDataPaths, _file);\n    }\n    return true;\n}\n\n\n"
  },
  {
    "path": "SoA/FragFile.h",
    "content": "#pragma once\n\n#include \"Vorb/types.h\"\n\n// Header For Each Data Path That Allows Fragmented Functionality\nclass FragHeader;\n\n// A File That Stores Multiple Data Paths In Fragmented Blocks\nclass FragFile {\npublic:\n    FragFile(i32 numPaths, const cString path, bool isReadonly);\n    ~FragFile();\n\n    // Point To A Data Path\n    void setDataPath(i32 p);\n\n    // Total Number Of Data Paths Found In The File\n    i32 getNumDataPaths() const {\n        return _numDataPaths;\n    }\n\n    // Size In Bytes Of The Data Path\n    i32 getDataPathSize() const;\n\n    // Reads An Entire Data Path Into A Buffer\n    void read(void* buf);\n\n    // Appends Data Into The Current Data Path\n    void append(void* data, i32 sizeInBytes);\n    // Overwrites/Appends Data From An Offset Into The Current Data Path\n    void overwrite(void* data, i32 fileDataOffset);\n\n    // Defragment The File By Using A Temporary File Name (Will Perform A Swap/Delete On The Temp File)\n    void defragment(const cString tmpFileName);\n\n    // OS File Operations\n    void flush();\n    void close();\nprivate:\n    // IO Helpers\n    bool openReadonlyFile(const cString path);\n    bool openWritingFile(const cString path);\n\n    // The Actual File\n    FILE* _file;\n\n    // Which Data Path To Read From\n    i32 _curPath;\n\n    // Data Path Information\n    const i32 _numDataPaths;\n    const i32 _headerSizeInBytes;\n    FragHeader* _headers;\n};"
  },
  {
    "path": "SoA/FreeMoveComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FreeMoveComponentUpdater.h\"\n\n#include \"SpaceSystem.h\"\n#include \"GameSystem.h\"\n#include \"Constants.h\"\n\nvoid FreeMoveComponentUpdater::update(GameSystem* gameSystem, SpaceSystem* spaceSystem) {\n    //TODO(Ben): A lot of temporary code here\n    f64v3 forward, right, up;\n\n    for (auto& it : gameSystem->freeMoveInput) {\n        auto& fmcmp = it.second;\n        auto& physcmp = gameSystem->physics.get(fmcmp.physicsComponent);\n\n        f64q* orientation;\n        f64 acceleration = (f64)fmcmp.speed * 0.01;\n        // If there is a voxel component, we use voxel position\n        if (physcmp.voxelPosition) {\n            // No acceleration on voxels\n            physcmp.velocity = f64v3(0.0);\n            acceleration = 1.0;\n            auto& vpCmp = gameSystem->voxelPosition.get(physcmp.voxelPosition);\n            //f64 radius = spaceSystem->sphericalGravity.get(vpCmp.parentVoxel).radius;\n            orientation = &vpCmp.orientation;\n            if (fmcmp.superSpeed) {\n                static const f64 SS_Mult = 0.01;\n                acceleration *= glm::min(600.0, glm::max(2.0, (SS_Mult * vpCmp.gridPosition.pos.y))); // temporary\n            }\n        } else {\n            auto& spCmp = gameSystem->spacePosition.get(physcmp.spacePosition);\n            f64 radius = spaceSystem->sphericalGravity.get(spCmp.parentGravity).radius;\n            orientation = &spCmp.orientation;\n            acceleration *= KM_PER_VOXEL;\n            if (fmcmp.superSpeed) {\n                static const f64 SS_Mult = 0.1;\n                acceleration *= glm::max(2.0, (SS_Mult * (glm::length(spCmp.position) - radius))); // temporary, assumes a parent\n            }\n        }\n       \n        // Calculate velocity vector from inputs and speed\n        if (fmcmp.tryMoveForward) {\n            forward = *orientation * f64v3(0.0, 0.0, 1.0);\n            physcmp.velocity += forward * acceleration;\n        } else if (fmcmp.tryMoveBackward) {\n            forward = *orientation * f64v3(0.0, 0.0, 1.0);\n            physcmp.velocity -= forward * acceleration;\n        }\n\n        if (fmcmp.tryMoveRight) {\n            right = *orientation * f64v3(-1.0, 0.0, 0.0);\n            physcmp.velocity += right * acceleration;\n        } else if (fmcmp.tryMoveLeft) {\n            right = *orientation * f64v3(-1.0, 0.0, 0.0);\n            physcmp.velocity -= right * acceleration;\n        }\n\n        if (fmcmp.tryMoveUp) {\n            up = *orientation * f64v3(0.0, 1.0, 0.0);\n            physcmp.velocity += up * acceleration;\n        } else if (fmcmp.tryMoveDown) {\n            up = *orientation * f64v3(0.0, 1.0, 0.0);\n            physcmp.velocity -= up * acceleration;\n        }\n\n        #define ROLL_SPEED 0.7\n        if (fmcmp.tryRollLeft) {\n            forward = *orientation * f64v3(0.0, 0.0, 1.0);\n            *orientation = glm::angleAxis(-ROLL_SPEED, forward) * (*orientation);\n        } else if (fmcmp.tryRollRight) {\n            forward = *orientation * f64v3(0.0, 0.0, 1.0);\n            *orientation = glm::angleAxis(ROLL_SPEED, forward) * (*orientation);\n        }\n    }\n}\n\nvoid FreeMoveComponentUpdater::rotateFromMouse(GameSystem* gameSystem, FreeMoveInputComponent& cmp, float dx, float dy, float speed) {\n\n    auto& physcmp = gameSystem->physics.get(cmp.physicsComponent);\n\n    f64q* orientation;\n    // If there is a voxel component, we use voxel position\n    if (physcmp.voxelPosition) {\n        orientation = &gameSystem->voxelPosition.get(physcmp.voxelPosition).orientation;\n    } else {\n        orientation = &gameSystem->spacePosition.get(physcmp.spacePosition).orientation;\n    }\n\n    f64v3 right = *orientation * f64v3(1.0, 0.0, 0.0);\n    f64v3 up = *orientation * f64v3(0.0, 1.0, 0.0);\n\n    f64q upQuat = glm::angleAxis((f64)(dy * speed), right);\n    f64q rightQuat = glm::angleAxis((f64)(dx * speed), up);\n\n    *orientation = upQuat * rightQuat * (*orientation);\n}\n"
  },
  {
    "path": "SoA/FreeMoveComponentUpdater.h",
    "content": "///\n/// FreeMoveComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates FreeMoveComponents\n///\n\n#pragma once\n\n#ifndef FreeMoveComponentUpdater_h__\n#define FreeMoveComponentUpdater_h__\n\nclass GameSystem;\nclass SpaceSystem;\nstruct FreeMoveInputComponent;\n\nclass FreeMoveComponentUpdater {\npublic:\n    void update(GameSystem* gameSystem, SpaceSystem* spaceSystem);\n    static void rotateFromMouse(GameSystem* gameSystem, FreeMoveInputComponent& cmp, float dx, float dy, float speed);\n};\n\n#endif // FreeMoveComponentUpdater_h__"
  },
  {
    "path": "SoA/Frustum.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Frustum.h\"\n\n#include \"Constants.h\"\n\nvoid Frustum::Plane::setNormalAndPoint(const f32v3 &normal, const f32v3 &point) {\n    this->normal = glm::normalize(normal);\n    d = -(glm::dot(this->normal, point));\n}\n\nvoid Frustum::Plane::setCoefficients(float a, float b, float c, float d) {\n    //compute the length of the vector\n    float l = glm::length(f32v3(a, b, c));\n    // normalize the vector\n    normal = f32v3(a / l, b / l, c / l);\n    // and divide d by th length as well\n    this->d = d / l;\n}\n\nfloat Frustum::Plane::distance(const f32v3 &p) const {\n    return (d + glm::dot(normal, p));\n}\n\nvoid Frustum::setCamInternals(float fov, float aspectRatio, float znear, float zfar) {\n#define RADIANS_PER_DEGREE M_PI / 180.0f\n    // store the information\n    m_fov = fov;\n    m_aspectRatio = aspectRatio;\n    m_znear = znear;\n    m_zfar = zfar;\n  \n    // compute width and height of the near and far plane sections\n    float tang = (float)tan(RADIANS_PER_DEGREE * fov * 0.5f);\n    m_nh = m_znear * tang;\n    m_nw = m_nh * m_aspectRatio;\n    m_fh = m_zfar  * tang;\n    m_fw = m_fh * m_aspectRatio;\n}\n\nvoid Frustum::updateFromWVP(const f32m4& WVP) {\n    m_planes[NEARP].setCoefficients(\n        WVP[0][2] + WVP[0][3],\n        WVP[1][2] + WVP[1][3],\n        WVP[2][2] + WVP[2][3],\n        WVP[3][2] + WVP[3][3]);\n    m_planes[FARP].setCoefficients(\n        -WVP[0][2] + WVP[0][3],\n        -WVP[1][2] + WVP[1][3],\n        -WVP[2][2] + WVP[2][3],\n        -WVP[3][2] + WVP[3][3]);\n    m_planes[BOTTOMP].setCoefficients(\n        WVP[0][1] + WVP[0][3],\n        WVP[1][1] + WVP[1][3],\n        WVP[2][1] + WVP[2][3],\n        WVP[3][1] + WVP[3][3]);\n    m_planes[TOPP].setCoefficients(\n        -WVP[0][1] + WVP[0][3],\n        -WVP[1][1] + WVP[1][3],\n        -WVP[2][1] + WVP[2][3],\n        -WVP[3][1] + WVP[3][3]);\n    m_planes[LEFTP].setCoefficients(\n        WVP[0][0] + WVP[0][3],\n        WVP[1][0] + WVP[1][3],\n        WVP[2][0] + WVP[2][3],\n        WVP[3][0] + WVP[3][3]);\n    m_planes[RIGHTP].setCoefficients(\n        -WVP[0][0] + WVP[0][3],\n        -WVP[1][0] + WVP[1][3],\n        -WVP[2][0] + WVP[2][3],\n        -WVP[3][0] + WVP[3][3]);\n}\n\nvoid Frustum::update(const f32v3& position, const f32v3& dir, const f32v3& up) {\n\n    f32v3 nc, fc, X, Y, Z;\n\n    // Compute the Z axis of camera\n    // This axis points in the opposite direction from \n    // the looking direction\n    Z = glm::normalize(position - dir);\n\n    // X axis of camera with given \"up\" vector and Z axis\n    X = glm::normalize(glm::cross(up, Z));\n\n    // The real \"up\" vector is the cross product of Z and X\n    Y = glm::cross(Z, X);\n\n    // compute the centers of the near and far planes\n    nc = position - Z * m_znear;\n    fc = position - Z * m_zfar;\n\n    m_planes[NEARP].setNormalAndPoint(-Z, nc);\n    m_planes[FARP].setNormalAndPoint(Z, fc);\n\n    f32v3 aux, normal;\n\n    aux = glm::normalize((nc + Y * m_nh) - position);\n    normal = glm::cross(aux, X);\n    m_planes[TOPP].setNormalAndPoint(normal, nc + Y * m_nh);\n\n    aux = glm::normalize((nc - Y * m_nh) - position);\n    normal = glm::cross(X, aux);\n    m_planes[BOTTOMP].setNormalAndPoint(normal, nc - Y * m_nh);\n\n    aux = glm::normalize((nc - X * m_nw) - position);\n    normal = glm::cross(aux, Y);\n    m_planes[LEFTP].setNormalAndPoint(normal, nc - X * m_nw);\n\n    aux = glm::normalize((nc + X * m_nw) - position);\n    normal = glm::cross(Y, aux);\n    m_planes[RIGHTP].setNormalAndPoint(normal, nc + X * m_nw);\n}\n\nbool Frustum::pointInFrustum(const f32v3& pos) const {\n    for (int p = 0; p < 4; p++) { //*************************************** IGNORING FAR AND NEAR CLIPPING PLANE\n        if (m_planes[p].distance(pos) <= 0) return false;\n    }\n    return true;\n}\n\nbool Frustum::sphereInFrustum(const f32v3& pos, float radius) const {\n    for (int p = 0; p < 4; p++) { //*************************************** IGNORING FAR AND NEAR CLIPPING PLANE\n        if (m_planes[p].distance(pos) <= -radius) return false;\n    }\n    return true;\n}\n"
  },
  {
    "path": "SoA/Frustum.h",
    "content": "///\n/// Frustum.h\n/// Vorb Engine\n///\n/// Created by Benjamin Arnold on 24 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// This file implements a frustum used for frustum culling\n///\n\n#pragma once\n\n#ifndef Frustum_h__\n#define Frustum_h__\n\n#include \"Vorb/types.h\"\n\nclass Frustum {\npublic:\n\n    enum Planes {\n        RIGHTP = 0, LEFTP, BOTTOMP,\n        TOPP, FARP, NEARP\n    };\n\n    class Plane {\n    public:\n        void setNormalAndPoint(const f32v3 &normal, const f32v3 &point);\n        void setCoefficients(float a, float b, float c, float d);\n        float distance(const f32v3 &p) const;\n\n        f32v3 normal;\n        float d;\n    };\n\n    /// Sets internal camera properties. Needed for update()\n    void setCamInternals(float fov, float aspectRatio, float znear, float zfar);\n\n    /// Updates the frustum with the projection and view matrix\n    /// @param MVP: World-View-Projection matrix of camera\n    void updateFromWVP(const f32m4& WVP);\n\n    /// Updates the frustum with the geometric information\n    void update(const f32v3& position, const f32v3& dir, const f32v3& up);\n\n    /// Checks if a point is in the frustum\n    /// @param pos: The position of the point\n    /// @return true if it is in the frustum\n    bool pointInFrustum(const f32v3& pos) const;\n\n    /// Checks if a sphere is in the frustum\n    /// @param pos: Center position of the sphere\n    /// @param radius: Radius of the sphere\n    /// @return true if it is in the frustum\n    bool sphereInFrustum(const f32v3& pos, float radius) const;\nprivate:\n    float m_fov = 0.0f; ///< Vertical field of view in degrees\n    float m_aspectRatio = 0.0f; ///< Screen aspect ratio\n    float m_znear = 0.0f; ///< Near clipping plane\n    float m_zfar = 0.0f; ///< Far clipping plane\n    float m_nh = 0.0f; ///< Near plane height\n    float m_nw = 0.0f; ///< Near plane Width\n    float m_fh = 0.0f; ///< Far plane height\n    float m_fw = 0.0f; ///< Far plane Width\n    Plane m_planes[6]; ///< The actual frustum data\n};\n\n#endif // Frustum_h__"
  },
  {
    "path": "SoA/FrustumComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FrustumComponentUpdater.h\"\n\n#include \"GameSystem.h\"\n\nvoid FrustumComponentUpdater::update(OUT GameSystem* gameSystem) {\n    f64q orientation;\n    f32v3 up;\n    f32v3 dir;\n    const f32v3 pos(0.0f); ///< Always treat as origin for precision\n    for (auto& it : gameSystem->frustum) {\n        auto& cmp = it.second;\n        \n        // Get orientation based on position and head\n        if (cmp.voxelPosition) {\n            auto& vpCmp = gameSystem->voxelPosition.get(cmp.voxelPosition);\n            orientation = vpCmp.orientation;     \n        } else {\n            auto& spCmp = gameSystem->spacePosition.get(cmp.spacePosition);\n            orientation = spCmp.orientation;\n        }\n        if (cmp.head) {\n            auto& hCmp = gameSystem->head.get(cmp.head);\n            orientation = orientation * hCmp.relativeOrientation;\n        }\n\n        up = orientation * f64v3(0.0, 1.0, 0.0);\n        dir = orientation * f64v3(0.0, 0.0, 1.0);\n\n        cmp.frustum.update(pos, dir, up);\n    }\n}\n"
  },
  {
    "path": "SoA/FrustumComponentUpdater.h",
    "content": "///\n/// FrustumComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 25 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates frustum components\n///\n\n#pragma once\n\n#ifndef FrustumComponentUpdater_h__\n#define FrustumComponentUpdater_h__\n\n#include \"Vorb/decorators.h\"\n\nclass GameSystem;\n\nclass FrustumComponentUpdater {\npublic:\n    /// Updates frustum components\n    /// @param gameSystem: Game ECS\n    void update(OUT GameSystem* gameSystem);\n};\n\n#endif // FrustumComponentUpdater_h__\n"
  },
  {
    "path": "SoA/GameManager.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameManager.h\"\n\n#ifdef VORB_OS_WINDOWS\n#include <direct.h> //for mkdir windows\n#endif//VORB_OS_WINDOWS\n\n#include <ctime>\n\n#include <Vorb/ThreadPool.h>\n#include <Vorb/utils.h>\n\n#include \"BlockData.h\"\n#include \"CAEngine.h\"\n#include \"Chunk.h\"\n#include \"ChunkIOManager.h\"\n#include \"DebugRenderer.h\"\n#include \"InputMapper.h\"\n#include \"Inputs.h\"\n#include \"SoaOptions.h\"\n#include \"VRayHelper.h\"\n#include \"WSO.h\"\n#include \"WSOAtlas.h\"\n#include \"WSOData.h\"\n#include \"WSOScanner.h\"\n\n#include \"VoxelEditor.h\"\n\nbool GameManager::gameInitialized = false;\nbool GameManager::_systemsInitialized = false;\nfloat GameManager::fogStart, GameManager::fogEnd;\n\nVoxelEditor* GameManager::voxelEditor = nullptr;\nWSOAtlas* GameManager::wsoAtlas = nullptr;\nWSOScanner* GameManager::wsoScanner = nullptr;\nvg::TextureCache* GameManager::textureCache = nullptr;\n\nvoid GameManager::initializeSystems() {\n    if (_systemsInitialized == false) {\n        voxelEditor = new VoxelEditor();\n        wsoAtlas = new WSOAtlas();\n        wsoAtlas->load(\"Data\\\\WSO\\\\test.wso\");\n        wsoScanner = new WSOScanner(wsoAtlas);\n        textureCache = new vg::TextureCache();\n\n        _systemsInitialized = true;\n    }\n}\n\nvoid GameManager::registerTexturesForLoad() {\n\n    //texturePackLoader->registerTexture(\"FarTerrain/location_marker.png\");\n    //texturePackLoader->registerTexture(\"FarTerrain/terrain_texture.png\", &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n    //texturePackLoader->registerTexture(\"FarTerrain/normal_leaves_billboard.png\");\n    //texturePackLoader->registerTexture(\"FarTerrain/pine_leaves_billboard.png\");\n    //texturePackLoader->registerTexture(\"FarTerrain/mushroom_cap_billboard.png\");\n    //texturePackLoader->registerTexture(\"FarTerrain/tree_trunk_1.png\");\n    //texturePackLoader->registerTexture(\"Blocks/Liquids/water_normal_map.png\", &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n\n    //texturePackLoader->registerTexture(\"Sky/StarSkybox/front.png\");\n    //texturePackLoader->registerTexture(\"Sky/StarSkybox/right.png\");\n    //texturePackLoader->registerTexture(\"Sky/StarSkybox/top.png\");\n    //texturePackLoader->registerTexture(\"Sky/StarSkybox/left.png\");\n    //texturePackLoader->registerTexture(\"Sky/StarSkybox/bottom.png\");\n    //texturePackLoader->registerTexture(\"Sky/StarSkybox/back.png\");\n\n    //texturePackLoader->registerTexture(\"FarTerrain/water_noise.png\", &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n    //texturePackLoader->registerTexture(\"Particle/ball_mask.png\");\n\n    //texturePackLoader->registerTexture(\"GUI/crosshair.png\");\n}\n\nvoid GameManager::getTextureHandles() {\n\n}\n\nvoid GameManager::saveState() {\n    savePlayerState();\n  //  saveOptions();\n  //  voxelWorld->getChunkManager().saveAllChunks();\n}\n\nvoid GameManager::savePlayerState() {\n   // fileManager.savePlayerFile(player);\n}\n\nbool isSolidBlock(const i32& blockID VORB_UNUSED) {\n    return true; // return blockID && (blockID < LOWWATER || blockID > FULLWATER);\n}\n\nvoid GameManager::clickDragRay(ChunkManager* chunkManager VORB_UNUSED, Player* player VORB_UNUSED, bool isBreakRay VORB_UNUSED) {\n#define MAX_RANGE 120.0f\n\n    //VoxelRayQuery rq;\n    //if (isBreakRay) {\n    //    // Obtain The Simple Query\n    //    rq = VRayHelper::getQuery(player->getChunkCamera().getPosition(), player->chunkDirection(), MAX_RANGE, chunkManager, isSolidBlock);\n\n    //    // Check If Something Was Picked\n    //    if (rq.distance > MAX_RANGE || rq.id == NONE) return;\n    //} else {\n    //    // Obtain The Full Query\n    //    VoxelRayFullQuery rfq = VRayHelper::getFullQuery(player->getChunkCamera().getPosition(), player->chunkDirection(), MAX_RANGE, chunkManager, isSolidBlock);\n\n    //    // Check If Something Was Picked\n    //    if (rfq.inner.distance > MAX_RANGE || rfq.inner.id == NONE) return;\n\n    //    // We Want This Indexing Information From The Query\n    //    rq = rfq.outer;\n    //}\n\n    //if (rq.chunk == nullptr) {\n    //    return;\n    //}\n\n    //i32v3 position = rq.location;\n    //if (voxelEditor->isEditing() == false) {\n    //    voxelEditor->setStartPosition(position);\n    //    voxelEditor->setEndPosition(position);\n    //} else {\n    //    voxelEditor->setEndPosition(position);\n    //}\n}\nvoid GameManager::scanWSO(ChunkManager* chunkManager VORB_UNUSED, Player* player VORB_UNUSED) {\n\n#define SCAN_MAX_DISTANCE 20.0\n    /* VoxelRayQuery rq = VRayHelper::getQuery(\n         player->getChunkCamera().getPosition(),\n         player->getChunkCamera().getDirection(),\n         SCAN_MAX_DISTANCE,\n         chunkManager,\n         isSolidBlock\n         );\n         if (rq.distance > SCAN_MAX_DISTANCE || rq.id == 0) return;\n\n         auto wsos = wsoScanner->scanWSOs(rq.location, chunkManager);\n\n         for (i32 i = 0; i < wsos.size(); i++) {\n         f32v3 wsoPos(wsos[i]->position);\n         f32v3 wsoSize(wsos[i]->data->size);\n         wsoPos += wsoSize * 0.5f;\n\n         debugRenderer->drawCube(wsoPos, wsoSize + 0.3f, f32v4(1, 1, 0, 0.1f), 2.0);\n\n         delete wsos[i];\n         }*/\n}\n\nvoid GameManager::onQuit() {\n    // GLuint st = SDL_GetTicks();\n    saveState();\n}\n\nvoid GameManager::endSession() {\n    onQuit();\n#ifdef _DEBUG \n    //_CrtDumpMemoryLeaks();\n#endif\n}"
  },
  {
    "path": "SoA/GameManager.h",
    "content": "#pragma once\n#include <deque>\n\n#include <Vorb/graphics/TextureCache.h>\n#include <Vorb/Vorb.h>\n\n#include \"WorldStructs.h\"\n\nclass ChunkSlot;\nclass Player;\nclass VoxelEditor;\nclass Chunk;\nclass ChunkManager;\n\n//This is where the main game components are contained\n// TODO(Ben): Dependency injection.\nclass GameManager\n{\npublic:\n\n    static void initializeSystems();\n    static void registerTexturesForLoad();\n    static void getTextureHandles();\n\n    static void saveState();\n    static void savePlayerState();\n\n    static void clickDragRay(ChunkManager* chunkManager, Player* player, bool isBreakRay);\n    static void scanWSO(ChunkManager* chunkManager, Player* player);\n    static void onQuit();\n    static void endSession();\n\n    static class VoxelEditor* voxelEditor;\n\n    static bool gameInitialized;\n    static float fogStart, fogEnd;\n    static class WSOAtlas* wsoAtlas;\n    static class WSOScanner* wsoScanner;\n    static class vg::TextureCache* textureCache;\n\nprivate:\n    static bool _systemsInitialized;\n\n};\n\n"
  },
  {
    "path": "SoA/GamePlayScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GamePlayScreen.h\"\n\n#include <Vorb/colors.h>\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/utils.h>\n\n#include \"App.h\"\n#include \"ChunkMesh.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkMesher.h\"\n#include \"ChunkRenderer.h\"\n#include \"Collision.h\"\n#include \"DebugRenderer.h\"\n#include \"DevConsole.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"GameSystem.h\"\n#include \"GameSystemUpdater.h\"\n#include \"HeadComponentUpdater.h\"\n#include \"InputMapper.h\"\n#include \"Inputs.h\"\n#include \"MainMenuScreen.h\"\n#include \"ParticleMesh.h\"\n#include \"SoaEngine.h\"\n#include \"SoaOptions.h\"\n#include \"SoAState.h\"\n#include \"SpaceSystem.h\"\n#include \"SpaceSystemUpdater.h\"\n#include \"TerrainPatch.h\"\n#include \"VRayHelper.h\"\n#include \"VoxelEditor.h\"\n#include \"soaUtils.h\"\n\nGameplayScreen::GameplayScreen(const App* app, const MainMenuScreen* mainMenuScreen) :\n    IAppScreen<App>(app),\n    m_mainMenuScreen(mainMenuScreen),\n    m_soaState(nullptr),\n    m_inputMapper(nullptr),\n    controller(),\n    m_spaceSystemUpdater(nullptr),\n    m_gameSystemUpdater(nullptr),\n    m_updateThread(nullptr),\n    m_threadRunning(false),\n    m_prevRenderState(nullptr),\n    m_shouldReloadTarget(false),\n    m_shouldReloadShaders(false),\n    m_shouldToggleDevConsole(false){\n    // Empty\n}\n\nGameplayScreen::~GameplayScreen() {\n    // Empty\n}\n\ni32 GameplayScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 GameplayScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid GameplayScreen::build() {\n    // Empty\n}\n\nvoid GameplayScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Destruction happens in onExit\n}\n\nvoid GameplayScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n#ifdef VORB_OS_WINDOWS\n    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);\n#else\n    struct sched_param params;\n \n    params.sched_priority = sched_get_priority_max(SCHED_FIFO);\n    pthread_setschedparam(pthread_self(), SCHED_FIFO, &params);\n#endif\n\n    m_soaState = m_mainMenuScreen->getSoAState();\n\n    controller.startGame(m_soaState);\n\n    initInput();\n\n    initConsole();\n\n    m_spaceSystemUpdater = std::make_unique<SpaceSystemUpdater>();\n    m_gameSystemUpdater = std::make_unique<GameSystemUpdater>(m_soaState, m_inputMapper);\n\n    // Initialize the PDA\n    m_pda.init(this);\n\n    // Initialize the Pause Menu\n    m_pauseMenu.init(this);\n\n    // Set up the rendering\n    initRenderPipeline();\n\n    // Initialize and run the update thread\n    m_updateThread = new std::thread(&GameplayScreen::updateThreadFunc, this);\n\n    SDL_SetRelativeMouseMode(SDL_TRUE);\n}\n\nvoid GameplayScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    m_inputMapper->stopInput();\n    m_hooks.dispose();\n\n    SoaEngine::destroyGameSystem(m_soaState);\n\n    m_threadRunning = false;\n    m_updateThread->join();\n    delete m_updateThread;\n    m_pda.destroy();\n    //m_renderPipeline.destroy(true);\n    m_pauseMenu.destroy();\n\n    m_devConsoleView.dispose();\n}\n\n/// This update function runs on the render thread\nvoid GameplayScreen::update(const vui::GameTime& gameTime VORB_UNUSED) {\n\n    if (m_shouldReloadShaders) {\n        m_renderer.reloadShaders();\n        m_shouldReloadShaders = false;\n    }\n\n    if (m_shouldToggleDevConsole) {\n        m_shouldToggleDevConsole = false;\n        DevConsole::getInstance().toggleFocus();\n    }\n\n    m_spaceSystemUpdater->glUpdate(m_soaState);\n\n    // TODO(Ben): Move to glUpdate for voxel component\n    // TODO(Ben): Don't hardcode for a single player\n    auto& vpCmp = m_soaState->gameSystem->voxelPosition.getFromEntity(m_soaState->clientState.playerEntity);\n    m_soaState->clientState.chunkMeshManager->update(vpCmp.gridPosition.pos, true);\n\n    // Update the PDA\n    if (m_pda.isOpen()) m_pda.update();\n\n    // Updates the Pause Menu\n    if (m_pauseMenu.isOpen()) m_pauseMenu.update();\n\n    // Check for target reload\n    if (m_shouldReloadTarget) {\n        m_reloadLock.lock();\n        printf(\"Reloading Target\\n\");\n        m_soaState->threadPool->clearTasks();\n        std::this_thread::sleep_for(std::chrono::microseconds(200));\n        SoaEngine::reloadSpaceBody(m_soaState, m_soaState->clientState.startingPlanet, nullptr);\n        m_shouldReloadTarget = false;\n        m_reloadLock.unlock();\n    }\n}\n\nvoid GameplayScreen::updateECS() {\n    SpaceSystem* spaceSystem = m_soaState->spaceSystem;\n    GameSystem* gameSystem = m_soaState->gameSystem;\n\n    // Time warp\n    const f64 TIME_WARP_SPEED = 100.0 + (f64)m_inputMapper->getInputState(INPUT_SPEED_TIME) * 1000.0;\n    if (m_inputMapper->getInputState(INPUT_TIME_BACK)) {\n        m_soaState->time -= TIME_WARP_SPEED;\n    }\n    if (m_inputMapper->getInputState(INPUT_TIME_FORWARD)) {\n        m_soaState->time += TIME_WARP_SPEED;\n    }\n\n    m_soaState->time += m_soaState->timeStep;\n    // TODO(Ben): Don't hardcode for a single player\n    auto& spCmp = gameSystem->spacePosition.getFromEntity(m_soaState->clientState.playerEntity);\n    auto parentNpCmpId = spaceSystem->sphericalGravity.get(spCmp.parentGravity).namePositionComponent;\n    auto& parentNpCmp = spaceSystem->namePosition.get(parentNpCmpId);\n    // Calculate non-relative space position\n    f64v3 trueSpacePosition = spCmp.position + parentNpCmp.position;\n\n    m_spaceSystemUpdater->update(m_soaState,\n                                 trueSpacePosition,\n                                 m_soaState->gameSystem->voxelPosition.getFromEntity(m_soaState->clientState.playerEntity).gridPosition.pos);\n\n    m_gameSystemUpdater->update(gameSystem, spaceSystem, m_soaState);\n}\n\nvoid GameplayScreen::updateMTRenderState() {\n    MTRenderState* state = m_renderStateManager.getRenderStateForUpdate();\n\n    SpaceSystem* spaceSystem = m_soaState->spaceSystem;\n    GameSystem* gameSystem = m_soaState->gameSystem;\n    // Set all space positions\n    for (auto& it : spaceSystem->namePosition) {\n        state->spaceBodyPositions[it.first] = it.second.position;\n    }\n    // Set camera position\n    auto& spCmp = gameSystem->spacePosition.getFromEntity(m_soaState->clientState.playerEntity);\n    state->spaceCameraPos = spCmp.position;\n    state->spaceCameraOrientation = spCmp.orientation;\n\n    // Set player data\n    auto& physics = gameSystem->physics.getFromEntity(m_soaState->clientState.playerEntity);\n    if (physics.voxelPosition) {\n        state->playerHead = gameSystem->head.getFromEntity(m_soaState->clientState.playerEntity);\n        state->playerPosition = gameSystem->voxelPosition.get(physics.voxelPosition);\n        state->hasVoxelPos = true;\n    } else {\n        state->hasVoxelPos = false;\n    }\n    // Debug chunk grid\n    if (m_renderer.stages.chunkGrid.isActive() && m_soaState->clientState.startingPlanet) {\n        // TODO(Ben): This doesn't let you go to different planets!!!\n        auto& svcmp = spaceSystem->sphericalVoxel.getFromEntity(m_soaState->clientState.startingPlanet);\n        auto& vpCmp = gameSystem->voxelPosition.getFromEntity(m_soaState->clientState.playerEntity);\n        state->debugChunkData.clear();\n        if (svcmp.chunkGrids) {\n            for (ChunkHandle chunk : svcmp.chunkGrids[vpCmp.gridPosition.face].acquireActiveChunks()) {\n                state->debugChunkData.emplace_back();\n                state->debugChunkData.back().genLevel = chunk->genLevel;\n                state->debugChunkData.back().voxelPosition = chunk->getVoxelPosition().pos;\n            }\n            svcmp.chunkGrids[vpCmp.gridPosition.face].releaseActiveChunks();\n        }\n    } else {\n        std::vector<DebugChunkData>().swap(state->debugChunkData);\n    }\n\n    m_renderStateManager.finishUpdating();\n}\n\nvoid GameplayScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    globalRenderAccumulationTimer.start(\"Draw\");\n\n    const MTRenderState* renderState;\n    // Don't render the same state twice.\n    if ((renderState = m_renderStateManager.getRenderStateForRender()) == m_prevRenderState) {\n        return;\n    }\n    m_prevRenderState = renderState;\n\n    // Set renderState and draw everything\n    m_renderer.setRenderState(renderState);\n    m_renderer.render();\n    globalRenderAccumulationTimer.stop();\n\n    // Draw dev console\n    m_devConsoleView.update(0.01f);\n    if (DevConsole::getInstance().isFocused()) {\n        m_devConsoleView.render(m_game->getWindow().getViewportDims());\n    }\n\n    // Uncomment to time rendering\n    /*  static int g = 0;\n      if (++g == 10) {\n      globalRenderAccumulationTimer.printAll(true);\n      globalRenderAccumulationTimer.clear();\n      std::cout << \"\\n\";\n      g = 0;\n      }*/\n}\n\nvoid GameplayScreen::unPause() { \n    m_pauseMenu.close(); \n    SDL_SetRelativeMouseMode(SDL_TRUE);\n    m_soaState->isInputEnabled = true;\n}\n\ni32 GameplayScreen::getWindowWidth() const {\n    return m_app->getWindow().getWidth();\n}\n\ni32 GameplayScreen::getWindowHeight() const {\n    return m_app->getWindow().getHeight();\n}\n\nvoid GameplayScreen::initInput() {\n\n    m_inputMapper = new InputMapper;\n    initInputs(m_inputMapper);\n\n    m_inputMapper->get(INPUT_PAUSE).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) -> void {\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        m_soaState->isInputEnabled = false;\n    });\n    m_inputMapper->get(INPUT_GRID).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) -> void {\n        m_renderer.toggleChunkGrid();\n    });\n    m_inputMapper->get(INPUT_INVENTORY).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) -> void {\n       /* if (m_pda.isOpen()) {\n            m_pda.close();\n            SDL_SetRelativeMouseMode(SDL_TRUE);\n            m_soaState->isInputEnabled = true;\n            SDL_StartTextInput();\n        } else {\n            m_pda.open();\n            SDL_SetRelativeMouseMode(SDL_FALSE);\n            m_soaState->isInputEnabled = false;\n            SDL_StopTextInput();\n        }*/\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        m_inputMapper->stopInput();\n        m_soaState->isInputEnabled = false;\n    });\n    m_inputMapper->get(INPUT_NIGHT_VISION).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) -> void {\n        if (isInGame()) {\n            m_renderer.toggleNightVision();\n        }\n    });\n    m_inputMapper->get(INPUT_HUD).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) -> void {\n        m_renderer.cycleDevHud();\n    });\n    m_inputMapper->get(INPUT_NIGHT_VISION_RELOAD).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) -> void {\n        m_renderer.loadNightVision();\n    });\n\n    m_inputMapper->get(INPUT_RELOAD_SHADERS).downEvent += makeDelegate(this, &GameplayScreen::onReloadShaders);\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e VORB_MAYBE_UNUSED) {\n        if (isInGame()) {\n            SDL_SetRelativeMouseMode(SDL_TRUE);\n            m_soaState->isInputEnabled = true;\n        }\n    });\n\n    m_inputMapper->get(INPUT_RELOAD_TARGET).downEvent += makeDelegate(this, &GameplayScreen::onReloadTarget);\n\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonUp, [&](Sender s VORB_UNUSED, const vui::MouseButtonEvent& e VORB_UNUSED) {\n        if (GameManager::voxelEditor->isEditing()) {\n            //TODO(Ben): Edit voxels\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e VORB_MAYBE_UNUSED) {\n        SDL_SetRelativeMouseMode(SDL_TRUE);\n        m_inputMapper->startInput();\n        m_soaState->isInputEnabled = true;     \n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onFocusLost, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseEvent& e VORB_MAYBE_UNUSED) {\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        m_inputMapper->stopInput();\n        m_soaState->isInputEnabled = false;\n    });\n    \n    // Temporary dev console\n    // TODO(Ben): Don't use functor\n    vui::InputDispatcher::key.onKeyDown.addFunctor([&](Sender, const vui::KeyEvent& e VORB_UNUSED) {\n        if (e.keyCode == VKEY_GRAVE) {\n            m_shouldToggleDevConsole = true;\n            if (!DevConsole::getInstance().isFocused()) {\n                m_inputMapper->stopInput();\n                m_soaState->isInputEnabled = false;\n            } else {\n                m_inputMapper->startInput();\n                m_soaState->isInputEnabled = true;\n            }\n        }\n    }\n    );\n \n    { // Player movement events\n        vecs::ComponentID parkourCmp = m_soaState->gameSystem->parkourInput.getComponentID(m_soaState->clientState.playerEntity);\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_FORWARD).downEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).moveForward = true;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_FORWARD).upEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).moveForward = false;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_BACKWARD).downEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).moveBackward = true;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_BACKWARD).upEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).moveBackward = false;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_LEFT).downEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).moveLeft = true;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_LEFT).upEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).moveLeft = false;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_RIGHT).downEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).moveRight = true;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_RIGHT).upEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).moveRight = false;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_JUMP).downEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).jump = true;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_JUMP).upEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).jump = false;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_CROUCH).downEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).crouch = true;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_CROUCH).upEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).crouch = false;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_SPRINT).downEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).sprint = true;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_SPRINT).upEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).sprint = false;\n        });\n        // TODO(Ben): Different parkour input\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_SPRINT).downEvent, [=](Sender s VORB_UNUSED, ui32 a VORB_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).parkour = true;\n        });\n        m_hooks.addAutoHook(m_inputMapper->get(INPUT_SPRINT).upEvent, [=](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n            m_soaState->gameSystem->parkourInput.get(parkourCmp).parkour = false;\n        });\n        m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e VORB_MAYBE_UNUSED) {\n            if (m_soaState->clientState.playerEntity) {\n                vecs::EntityID pid = m_soaState->clientState.playerEntity;\n                f64v3 pos = controller.getEntityEyeVoxelPosition(m_soaState, pid);\n                f32v3 dir = controller.getEntityViewVoxelDirection(m_soaState, pid);\n                auto& vp = m_soaState->gameSystem->voxelPosition.getFromEntity(pid);\n                vecs::ComponentID svid = vp.parentVoxel;\n                ChunkGrid& grid = m_soaState->spaceSystem->sphericalVoxel.get(svid).chunkGrids[vp.gridPosition.face];\n                VoxelRayFullQuery q = VRayHelper().getFullQuery(pos, dir, 100.0, grid);\n                m_soaState->clientState.voxelEditor.setStartPosition(q.outer.location);\n\n                std::cout << \"DIST \" << glm::length(f64v3(q.outer.location) - pos);\n                printVec(\"Start \", q.outer.location);\n                m_renderer.debugRenderer->drawLine(pos, pos + f64v3(dir) * 100.0, color::Red);\n            }\n        });\n        m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e VORB_MAYBE_UNUSED) {\n            if (m_soaState->clientState.playerEntity) {\n                vecs::EntityID pid = m_soaState->clientState.playerEntity;\n                f64v3 pos = controller.getEntityEyeVoxelPosition(m_soaState, pid);\n                f32v3 dir = controller.getEntityViewVoxelDirection(m_soaState, pid);\n                auto& vp = m_soaState->gameSystem->voxelPosition.getFromEntity(pid);\n                vecs::ComponentID svid = vp.parentVoxel;\n                ChunkGrid& grid = m_soaState->spaceSystem->sphericalVoxel.get(svid).chunkGrids[vp.gridPosition.face];\n                VoxelRayFullQuery q = VRayHelper().getFullQuery(pos, dir, 100.0, grid);\n                m_soaState->clientState.voxelEditor.setEndPosition(q.outer.location);\n                printVec(\"End \", q.outer.location);\n                ItemStack& iStack = m_soaState->gameSystem->inventory.getFromEntity(pid).items[0];\n\n                m_soaState->clientState.voxelEditor.editVoxels(grid, &iStack);\n            }\n        });\n        // Mouse movement\n        vecs::ComponentID headCmp = m_soaState->gameSystem->head.getComponentID(m_soaState->clientState.playerEntity);\n        m_hooks.addAutoHook(vui::InputDispatcher::mouse.onMotion, [=](Sender s VORB_MAYBE_UNUSED, const vui::MouseMotionEvent& e VORB_MAYBE_UNUSED) {\n            HeadComponentUpdater::rotateFromMouse(m_soaState->gameSystem, headCmp, -e.dx, e.dy, 0.002f);\n        });\n    }\n\n    vui::InputDispatcher::window.onClose += makeDelegate(this, &GameplayScreen::onWindowClose);\n\n    m_inputMapper->get(INPUT_SCREENSHOT).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 i VORB_MAYBE_UNUSED) {\n        m_renderer.takeScreenshot(); });\n    m_inputMapper->get(INPUT_DRAW_MODE).downEvent += makeDelegate(this, &GameplayScreen::onToggleWireframe);\n\n    m_inputMapper->startInput();\n}\n\nvoid GameplayScreen::initConsole() {\n    vui::GameWindow& window = m_game->getWindow();\n    // TODO(Ben): Dispose\n    m_devConsoleView.init(&DevConsole::getInstance(), 5,\n                          f32v2(20.0f, window.getHeight() - 60.0f),\n                          window.getWidth() - 40.0f);\n    DevConsole::getInstance().addCommand(\"exit\");\n    DevConsole::getInstance().addListener(\"exit\", [](void*, const nString&) {\n        exit(0);\n    }, nullptr);\n}\n\nvoid GameplayScreen::initRenderPipeline() {\n    m_renderer.debugRenderer = m_soaState->clientState.debugRenderer;\n}\n\n// TODO(Ben): Collision\n//void GamePlayScreen::updatePlayer() {\n\n   // m_player->update(m_inputManager, true, 0.0f, 0.0f);\n\n  //  Chunk **chunks = new Chunk*[8];\n  //  _player->isGrounded = 0;\n  //  _player->setMoveMod(1.0f);\n  //  _player->canCling = 0;\n  //  _player->collisionData.yDecel = 0.0f;\n\n  //  // Number of steps to integrate the collision over\n  //  for (int i = 0; i < PLAYER_COLLISION_STEPS; i++){\n  //      _player->gridPosition += (_player->velocity / (float)PLAYER_COLLISION_STEPS) * glSpeedFactor;\n  //      _player->facePosition += (_player->velocity / (float)PLAYER_COLLISION_STEPS) * glSpeedFactor;\n  //      _player->collisionData.clear();\n  //      GameManager::voxelWorld->getClosestChunks(_player->gridPosition, chunks); //DANGER HERE!\n  //      aabbChunkCollision(_player, &(_player->gridPosition), chunks, 8);\n  //      _player->applyCollisionData();\n  //  }\n\n  //  delete[] chunks;\n//}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               \n\n/// This is the update thread\nvoid GameplayScreen::updateThreadFunc() {\n    m_threadRunning = true;\n\n#ifdef VORB_OS_WINDOWS    \n    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);\n#else//VORB_OS_WINDOWS\n    struct sched_param params;\n \n    params.sched_priority = sched_get_priority_max(SCHED_FIFO);\n    pthread_setschedparam(pthread_self(), SCHED_FIFO, &params);\n#endif//VORB_OS_WINDOWS\n\n    FpsLimiter fpsLimiter;\n    fpsLimiter.init(60.0f);\n    // TODO(Matthew): This statement wasn't used, eventually log/display FPS.\n    //f32 fps;\n\n    static int saveStateTicks = SDL_GetTicks();\n\n    while (m_threadRunning) {\n        fpsLimiter.beginFrame();\n\n        m_reloadLock.lock();\n        updateECS(); // TODO(Ben): Entity destruction in this thread calls opengl stuff.....\n        updateMTRenderState();\n        m_reloadLock.unlock();\n\n        if (SDL_GetTicks() - saveStateTicks >= 20000) {\n            saveStateTicks = SDL_GetTicks();\n      //      savePlayerState();\n        }\n\n        //fps = fpsLimiter.endFrame();\n    }\n}\n\nvoid GameplayScreen::onReloadShaders(Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n    printf(\"Reloading Shaders\\n\");\n    m_shouldReloadShaders = true;\n}\nvoid GameplayScreen::onReloadTarget(Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n    m_shouldReloadTarget = true;\n}\n\nvoid GameplayScreen::onQuit(Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n    SoaEngine::destroyAll(m_soaState);\n    exit(0);\n}\n\nvoid GameplayScreen::onToggleWireframe(Sender s VORB_MAYBE_UNUSED, ui32 i VORB_MAYBE_UNUSED) {\n    m_renderer.toggleWireframe();\n}\n\nvoid GameplayScreen::onWindowClose(Sender s) {\n    onQuit(s, 0);\n}\n"
  },
  {
    "path": "SoA/GamePlayScreen.h",
    "content": "// \n//  GamePlayScreen.h\n//  Seed Of Andromeda\n//\n//  Created by Ben Arnold on 17 Oct 2014\n//  Copyright 2014 Regrowth Studios\n//  MIT License\n//  \n//  This file provides the implementation for the main\n//  gameplay screen. This will encompass all in game\n//  behavior.\n//\n\n#pragma once\n\n#ifndef GAMEPLAYSCREEN_H_\n#define GAMEPLAYSCREEN_H_\n\n#include <Vorb/Random.h>\n#include <Vorb/ui/IGameScreen.h>\n\n#include \"GameplayRenderer.h\"\n#include \"LoadMonitor.h\"\n#include \"MTRenderStateManager.h\"\n#include \"PDA.h\"\n#include \"PauseMenu.h\"\n#include \"SoaController.h\"\n#include \"DevConsoleView.h\"\n#include \"SpaceSystemUpdater.h\"\n\nclass App;\nclass GameStartState;\nclass GameSystem;\nclass GameSystemUpdater;\nclass InputMapper;\nclass MainMenuScreen;\nstruct SoaState;\nclass SpriteBatch;\nclass SpriteFont;\nclass TerrainMeshMessage;\n\ntemplate<typename... Params>\nclass GamePlayScreenDelegate;\nclass OnPauseKeyDown;\nclass OnFlyKeyDown;\nclass OnGridKeyDown;\nclass OnReloadTexturesKeyDown;\nclass OnReloadShadersKeyDown;\nclass OnInventoryKeyDown;\nclass OnReloadUIKeyDown;\nclass OnHUDKeyDown;\n\n// Each mode includes the previous mode\nenum DevUiModes {\n    DEVUIMODE_NONE,\n    DEVUIMODE_CROSSHAIR,\n    DEVUIMODE_HANDS,\n    DEVUIMODE_FPS,\n    DEVUIMODE_ALL\n};\n\nclass GameplayScreen : public vui::IAppScreen<App> {\n    friend class GameplayRenderer;\n    friend class GameplayLoadScreen;\npublic:\n    GameplayScreen(const App* app, const MainMenuScreen* mainMenuScreen);\n    ~GameplayScreen();\n\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\n\n    void unPause();\n\n    // Getters\n    i32 getWindowWidth() const;\n    i32 getWindowHeight() const;\n\n    bool isInGame() const {\n        return (!m_pda.isOpen() && !m_pauseMenu.isOpen());\n    }\n\nprivate:\n    /// Initializes event delegates and InputManager\n    void initInput();\n\n    /// Initializes dev console events\n    void initConsole();\n\n    /// Initializes the rendering\n    void initRenderPipeline();\n\n    /// The function that runs on the update thread. It handles\n    /// loading the planet in the background.\n    void updateThreadFunc();\n    \n    /// Updates the Entity component system\n    void updateECS();\n\n    /// Updates multi-threaded render state\n    void updateMTRenderState();\n\n    // --------------- Event handlers ---------------\n    void onReloadShaders(Sender s, ui32 a);\n    void onReloadTarget(Sender s, ui32 a);\n    void onQuit(Sender s, ui32 a);\n    void onToggleWireframe(Sender s, ui32 i);\n    void onWindowClose(Sender s);\n    // ----------------------------------------------\n\n    const MainMenuScreen* m_mainMenuScreen;\n    SoaState* m_soaState;\n\n    InputMapper* m_inputMapper;\n\n    PDA m_pda; ///< The PDA\n\n    PauseMenu m_pauseMenu; ///< The Pause Menu\n\n    DevConsoleView m_devConsoleView;\n\n    SoaController controller;\n    std::unique_ptr<SpaceSystemUpdater> m_spaceSystemUpdater;\n    std::unique_ptr<GameSystemUpdater> m_gameSystemUpdater;\n\n    std::thread* m_updateThread; ///< The thread that updates the planet. Runs updateThreadFunc()\n    volatile bool m_threadRunning; ///< True when the thread should be running\n\n    AutoDelegatePool m_hooks; ///< Input hooks reservoir\n    GameplayRenderer m_renderer; ///< This handles all rendering for the screen\n\n    MTRenderStateManager m_renderStateManager; ///< Manages the triple buffered render state\n    const MTRenderState* m_prevRenderState; ///< Render state use for previous draw\n\n    std::mutex m_reloadLock;\n    bool m_shouldReloadTarget;\n    bool m_shouldReloadShaders;\n    bool m_shouldToggleDevConsole;\n};\n\n#endif // GAMEPLAYSCREEN_H_\n"
  },
  {
    "path": "SoA/GameRenderParams.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameRenderParams.h\"\n\n#include <Vorb/utils.h>\n\n#include \"Camera.h\"\n#include \"GameManager.h\"\n\nvoid GameRenderParams::calculateParams(const f64v3& worldCameraPos VORB_UNUSED,\n                                       const Camera* ChunkCamera,\n                                       const VoxelPosition3D& voxPosition VORB_UNUSED,\n                                       f64 voxelWorldRadius VORB_UNUSED,\n                                       ChunkMeshManager* ChunkMeshmanager,\n                                       BlockPack* blocks,\n                                       BlockTexturePack* blockTexturePack,\n                                       bool IsUnderwater) {\n    chunkCamera = ChunkCamera;\n    isUnderwater = IsUnderwater;\n    this->blocks = blocks;\n    this->blockTexturePack = blockTexturePack;\n\n    chunkMeshmanager = ChunkMeshmanager;\n\n    // Calculate fog\n    sunlightDirection = glm::normalize(f32v3(0.7, 1.0, 0.5));\n    \n   // float theta = (f32)glm::dot(VoxelSpaceConversions::voxelToWorld(voxPosition, voxelWorldRadius), f64v3(lightPos));\n    f32 theta = 1.0f;\n    calculateFog(theta, isUnderwater);\n    calculateSunlight(theta);\n    sunlightColor = f32v3(1.0f);\n}\n\nvoid GameRenderParams::calculateFog(float theta, bool isUnderwater) {\n    \n#define FOG_THETA_MULT 100.0f\n#define FOG_THETA_OFFSET 50.0f\n    f32m4 VP;\n    //********************************* TODO: PRECOMPILED HEADERS for compilation speed?\n    float fogTheta = glm::clamp(theta, 0.0f, 1.0f);\n    fogStart = 0;\n    if (isUnderwater) {\n        float underwaterColor = fogTheta / 2.0f;\n        fogEnd = FOG_THETA_OFFSET + fogTheta * FOG_THETA_MULT;\n        fogColor[0] = underwaterColor;\n        fogColor[1] = underwaterColor;\n        fogColor[2] = underwaterColor;\n    } else {\n        fogEnd = 100000;\n        fogColor[0] = 1.0;\n        fogColor[1] = 1.0;\n        fogColor[2] = 1.0;\n    }\n}\n\nvoid GameRenderParams::calculateSunlight(float theta) {\n    // Calculate sunlight\n    #define AMB_MULT 0.76f\n    #define AMB_OFFSET 0.02f\n    #define MIN_THETA 0.01f\n    #define THETA_MULT 8.0f\n    #define SUN_COLOR_MAP_HEIGHT 64.0f\n    #define SUN_THETA_OFF 0.06f\n\n    /*   sunlightDirection = glm::normalize(f64v3(f64m4(glm::inverse(GameManager::player->worldRotationMatrix)) *\n           f64m4(GameManager::planet->invRotationMatrix) * f64v4(1.0, 0.0, 0.0, 1.0)));\n           */\n    float sunTheta = MAX(0.0f, theta + SUN_THETA_OFF);\n    if (sunTheta > 1) sunTheta = 1;\n    sunlightIntensity = sunTheta * AMB_MULT + AMB_OFFSET;\n    if (sunlightIntensity > 1.0f) sunlightIntensity = 1.0f;\n    float diffVal = 1.0f - sunlightIntensity;\n\n    if (theta < MIN_THETA) {\n        diffVal += (theta - MIN_THETA) * THETA_MULT;\n        if (diffVal < 0.0f) diffVal = 0.0f;\n    }\n\n    // TODO(Matthew): This was previously not used, determine if we should use or throw it.\n    // int sunHeight = (int)(theta * SUN_COLOR_MAP_HEIGHT);\n    // if (theta < 0) {\n    //     sunHeight = 0;\n    // }\n    sunlightColor = f32v3(1.0f) * diffVal;\n}"
  },
  {
    "path": "SoA/GameRenderParams.h",
    "content": "#pragma once\n\n#ifndef GameRenderParams_h__\n#define GameRenderParams_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include \"VoxelSpaceConversions.h\"\n\nclass ChunkMesh;\nclass Camera;\nclass ChunkMeshManager;\nclass BlockPack;\nclass BlockTexturePack;\n\nclass GameRenderParams {\npublic:\n    void calculateParams(const f64v3& worldCameraPos,\n                         const Camera* ChunkCamera,\n                         const VoxelPosition3D& voxPosition,\n                         f64 voxelWorldRadius,\n                         ChunkMeshManager* ChunkMeshmanager,\n                         BlockPack* blocks,\n                         BlockTexturePack* blockTexturePack,\n                         bool IsUnderwater);\n\n    f32v3 sunlightDirection;\n    f32v3 sunlightColor;  \n    float sunlightIntensity;\n    f32v3 fogColor;\n    float fogEnd;\n    float fogStart;\n    float lightActive;\n    const Camera* chunkCamera;\n    ChunkMeshManager* chunkMeshmanager;\n    BlockPack* blocks;\n    BlockTexturePack* blockTexturePack;\n    bool isUnderwater;\nprivate:\n    void calculateFog(float theta, bool isUnderwater);\n    void calculateSunlight(float theta);\n};\n\n#endif // GameRenderParams_h__"
  },
  {
    "path": "SoA/GameSystem.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameSystem.h\"\n\nGameSystem::GameSystem() : vecs::ECS() {\n    //Add all component tables\n    addComponentTable(GAME_SYSTEM_CT_AABBCOLLIDABLE_NAME, &aabbCollidable);\n    addComponentTable(GAME_SYSTEM_CT_FREEMOVEINPUT_NAME, &freeMoveInput);\n    addComponentTable(GAME_SYSTEM_CT_PARKOURINPUT_NAME, &parkourInput);\n    addComponentTable(GAME_SYSTEM_CT_PHYSICS_NAME, &physics);\n    addComponentTable(GAME_SYSTEM_CT_SPACEPOSITION_NAME, &spacePosition);\n    addComponentTable(GAME_SYSTEM_CT_VOXELPOSITION_NAME, &voxelPosition);\n    addComponentTable(GAME_SYSTEM_CT_FRUSTUM_NAME, &frustum);\n    addComponentTable(GAME_SYSTEM_CT_HEAD_NAME, &head);\n    addComponentTable(GAME_SYSTEM_CT_INVENTORY_NAME, &inventory);\n    addComponentTable(GAME_SYSTEM_CT_CHUNKSPHERE_NAME, &chunkSphere);\n    addComponentTable(GAME_SYSTEM_CT_ATTRIBUTES_NAME, &attributes);\n}\n\nvecs::ComponentID GameSystem::getComponent(const nString& name, vecs::EntityID eID) {\n    auto& table = *getComponentTable(name);\n    return table.getComponentID(eID);\n}"
  },
  {
    "path": "SoA/GameSystem.h",
    "content": "///\n/// GameSystem.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 10 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Entity Component System for the main game entities.\n///\n\n#pragma once\n\n#ifndef GameSystem_h__\n#define GameSystem_h__\n\n#include <Vorb/ecs/ComponentTable.hpp>\n#include <Vorb/ecs/ECS.h>\n\n#include \"GameSystemComponents.h\"\n\n#define GAME_SYSTEM_CT_AABBCOLLIDABLE_NAME \"AABBCollidable\"\n#define GAME_SYSTEM_CT_FREEMOVEINPUT_NAME \"FreeMoveInput\"\n#define GAME_SYSTEM_CT_PARKOURINPUT_NAME \"Parkour\"\n#define GAME_SYSTEM_CT_PHYSICS_NAME \"Physics\"\n#define GAME_SYSTEM_CT_SPACEPOSITION_NAME \"SpacePosition\"\n#define GAME_SYSTEM_CT_VOXELPOSITION_NAME \"VoxelPosition\"\n#define GAME_SYSTEM_CT_FRUSTUM_NAME \"Frustum\"\n#define GAME_SYSTEM_CT_HEAD_NAME \"Head\"\n#define GAME_SYSTEM_CT_INVENTORY_NAME \"Inventory\"\n#define GAME_SYSTEM_CT_CHUNKSPHERE_NAME \"ChunkSphere\"\n#define GAME_SYSTEM_CT_ATTRIBUTES_NAME \"Attributes\"\n\nclass GameSystem : public vecs::ECS {\npublic:\n    GameSystem();\n\n    AABBCollidableComponentTable aabbCollidable;\n    FreeMoveInputComponentTable freeMoveInput;\n    ParkourInputComponentTable parkourInput;\n    PhysicsComponentTable physics;\n    SpacePositionComponentTable spacePosition;\n    VoxelPositionComponentTable voxelPosition;\n    FrustumComponentTable frustum;\n    HeadComponentTable head;\n    InventoryComponentTable inventory;\n    ChunkSphereComponentTable chunkSphere;\n    AttributeComponentTable attributes;\n\n    vecs::ComponentID getComponent(const nString& name, vecs::EntityID eID);\n\nprivate:\n    VORB_NON_COPYABLE(GameSystem);\n};\n\n#endif // GameSystem_h__\n"
  },
  {
    "path": "SoA/GameSystemAssemblages.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameSystemAssemblages.h\"\n\n#include <Vorb/ecs/ECS.h>\n\n#include \"ChunkHandle.h\"\n#include \"ChunkSphereComponentUpdater.h\"\n#include \"GameSystem.h\"\n\nvecs::ComponentID GameSystemAssemblages::addFreeMoveInput(GameSystem* gameSystem, vecs::EntityID entity,\n                                                                vecs::ComponentID physicsComponent) {\n    vecs::ComponentID vmCmpId = gameSystem->addComponent(\"FreeMove\", entity);\n    auto& vmCmp = gameSystem->freeMoveInput.get(vmCmpId);\n    vmCmp.physicsComponent = physicsComponent;\n    return vmCmpId;\n}\n\nvoid GameSystemAssemblages::removeFreeMoveInput(GameSystem* gameSystem, vecs::EntityID entity) {\n    gameSystem->deleteComponent(\"FreeMove\", entity);\n}\n\nvecs::ComponentID GameSystemAssemblages::addPhysics(GameSystem* gameSystem, vecs::EntityID entity,\n                                                     f32 massKg, const f64v3& initialVel,\n                                                     vecs::ComponentID spacePositionComponent,\n                                                     vecs::ComponentID voxelPositionComponent /*= 0*/) {\n    vecs::ComponentID pCmpId = gameSystem->addComponent(\"Physics\", entity);\n    auto& pCmp = gameSystem->physics.get(pCmpId);\n    pCmp.spacePosition = spacePositionComponent;\n    pCmp.voxelPosition = voxelPositionComponent;\n    pCmp.velocity = initialVel;\n    pCmp.mass = massKg;\n    return pCmpId;\n}\n\nvoid GameSystemAssemblages::removePhysics(GameSystem* gameSystem, vecs::EntityID entity) {\n    gameSystem->deleteComponent(\"Physics\", entity);\n}\n\nvecs::ComponentID GameSystemAssemblages::addSpacePosition(GameSystem* gameSystem, vecs::EntityID entity,\n                                                           const f64v3& position, const f64q& orientation,\n                                                           vecs::EntityID parentEntity,\n                                                           vecs::ComponentID parentGravComponent /* = 0 */,\n                                                           vecs::ComponentID parentSphericalTerrainComponent /* = 0 */) {\n    vecs::ComponentID spCmpId = gameSystem->addComponent(\"SpacePosition\", entity);\n    auto& spCmp = gameSystem->spacePosition.get(spCmpId);\n    spCmp.position = position;\n    spCmp.orientation = orientation;\n    spCmp.parentEntity = parentEntity;\n    spCmp.parentGravity = parentGravComponent;\n    spCmp.parentSphericalTerrain = parentSphericalTerrainComponent;\n    return spCmpId;\n}\n\nvoid GameSystemAssemblages::removeSpacePosition(GameSystem* gameSystem, vecs::EntityID entity) {\n    gameSystem->deleteComponent(\"Space Position\", entity);\n}\n\nvecs::ComponentID GameSystemAssemblages::addAabbCollidable(GameSystem* gameSystem, vecs::EntityID entity,\n                                                                 const f32v3& box VORB_MAYBE_UNUSED, const f32v3& offset VORB_MAYBE_UNUSED) {\n    vecs::ComponentID abCmpId = gameSystem->addComponent(\"AABBCollidable\", entity);\n    auto& abCmp = gameSystem->aabbCollidable.get(abCmpId);\n    abCmp.box = f32v3(1.7f, 3.7f, 1.7f);\n    abCmp.offset = f32v3(0.0f);\n    return abCmpId;\n}\n\nvoid GameSystemAssemblages::removeAabbCollidable(GameSystem* gameSystem, vecs::EntityID entity) {\n    gameSystem->deleteComponent(\"AABBCollidable\", entity);\n}\n\nvecs::ComponentID GameSystemAssemblages::addVoxelPosition(GameSystem* gameSystem, vecs::EntityID entity,\n                                                                vecs::ComponentID parentVoxelComponent,\n                                                                const f64q& orientation,\n                                                                const VoxelPosition3D& gridPosition) {\n    // We need to transition to the voxels\n    vecs::ComponentID vpid = gameSystem->addComponent(\"VoxelPosition\", entity);\n    auto& vpcmp = gameSystem->voxelPosition.get(vpid);\n    vpcmp.parentVoxel = parentVoxelComponent;\n    vpcmp.gridPosition = gridPosition;\n    vpcmp.orientation = orientation;\n    return vpid;\n}\n\nvoid GameSystemAssemblages::removeVoxelPosition(GameSystem* gameSystem, vecs::EntityID entity) {\n    gameSystem->deleteComponent(\"VoxelPosition\", entity);\n}\n\nvecs::ComponentID GameSystemAssemblages::addChunkSphere(GameSystem* gameSystem, vecs::EntityID entity,\n                                 vecs::ComponentID voxelPosition,\n                                 const i32v3& centerPosition,\n                                 ui32 radius) {\n    vecs::ComponentID id = gameSystem->addComponent(\"ChunkSphere\", entity);\n    auto& cmp = gameSystem->chunkSphere.get(id);\n\n    cmp.radius = radius;\n    cmp.centerPosition = centerPosition;\n    cmp.offset = i32v3(0);\n    cmp.voxelPosition = voxelPosition;\n\n    cmp.radius = radius;\n    cmp.width = cmp.radius * 2 + 1;\n    cmp.layer = cmp.width * cmp.width;\n    cmp.size = cmp.layer * cmp.width;\n    return id;\n}\n\nvoid GameSystemAssemblages::removeChunkSphere(GameSystem* gameSystem, vecs::EntityID entity) {\n    gameSystem->deleteComponent(\"ChunkSphere\", entity);\n}\n\nextern vecs::ComponentID GameSystemAssemblages::addFrustumComponent(GameSystem* gameSystem, vecs::EntityID entity,\n                                                                     f32 fov, f32 aspectRatio, f32 znear, f32 zfar,\n                                                                     vecs::ComponentID spacePosition /* = 0 */,\n                                                                     vecs::ComponentID voxelPosition /* = 0 */,\n                                                                     vecs::ComponentID head /* = 0 */) {\n    vecs::ComponentID fid = gameSystem->addComponent(\"Frustum\", entity);\n    auto& fcmp = gameSystem->frustum.get(fid);\n    fcmp.frustum.setCamInternals(fov, aspectRatio, znear, zfar);\n    fcmp.spacePosition = spacePosition;\n    fcmp.voxelPosition = voxelPosition;\n    fcmp.head = head;\n    return fid;\n}\n\nextern void GameSystemAssemblages::removeFrustumComponent(GameSystem* gameSystem, vecs::EntityID entity) {\n    gameSystem->deleteComponent(\"Frustum\", entity);\n}\n\nextern vecs::ComponentID GameSystemAssemblages::addHeadComponent(GameSystem* gameSystem, vecs::EntityID entity, f64 neckLength) {\n    vecs::ComponentID hid = gameSystem->addComponent(\"Head\", entity);\n    auto& hcmp = gameSystem->head.get(hid);\n    hcmp.neckLength = neckLength;\n    return hid;\n}\n\nextern void GameSystemAssemblages::removeHeadComponent(GameSystem* gameSystem, vecs::EntityID entity) {\n    gameSystem->deleteComponent(\"Head\", entity);\n}\n"
  },
  {
    "path": "SoA/GameSystemAssemblages.h",
    "content": "///\n/// GameSystemAssemblages.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Component and entity assemblages for GameSystem\n///\n\n#pragma once\n\n#ifndef GameSystemAssemblages_h__\n#define GameSystemAssemblages_h__\n\n#include <Vorb/ecs/Entity.h>\n\nclass ChunkAccessor;\nclass GameSystem;\n\n#include \"GameSystemComponents.h\"\n\nnamespace GameSystemAssemblages {\n\n    /************************************************************************/\n    /* Component Factories                                                  */\n    /************************************************************************/\n    /// Free movement component\n    vecs::ComponentID addFreeMoveInput(GameSystem* gameSystem, vecs::EntityID entity,\n                                               vecs::ComponentID physicsComponent);\n    void removeFreeMoveInput(GameSystem* gameSystem, vecs::EntityID entity);\n    /// Physics component\n    vecs::ComponentID addPhysics(GameSystem* gameSystem, vecs::EntityID entity,\n                                         f32 massKg, const f64v3& initialVel,\n                                         vecs::ComponentID spacePositionComponent,\n                                         vecs::ComponentID voxelPositionComponent = 0);\n    void removePhysics(GameSystem* gameSystem, vecs::EntityID entity);\n    /// Space position component\n    vecs::ComponentID addSpacePosition(GameSystem* gameSystem, vecs::EntityID entity,\n                                               const f64v3& position, const f64q& orientation,\n                                               vecs::EntityID parentEntity,\n                                               vecs::ComponentID parentGravComponent = 0,\n                                               vecs::ComponentID parentSphericalTerrainComponent = 0);\n    void removeSpacePosition(GameSystem* gameSystem, vecs::EntityID entity);\n    /// AABB Collision component\n    vecs::ComponentID addAabbCollidable(GameSystem* gameSystem, vecs::EntityID entity,\n                                                const f32v3& box, const f32v3& offset);\n    void removeAabbCollidable(GameSystem* gameSystem, vecs::EntityID entity);\n    /// Voxel Position Component\n    vecs::ComponentID addVoxelPosition(GameSystem* gameSystem, vecs::EntityID entity,\n                                               vecs::ComponentID parentVoxelComponent,\n                                               const f64q& orientation,\n                                               const VoxelPosition3D& gridPosition);\n    void removeVoxelPosition(GameSystem* gameSystem, vecs::EntityID entity);\n    /// Voxel Position Component\n    vecs::ComponentID addChunkSphere(GameSystem* gameSystem, vecs::EntityID entity,\n                                     vecs::ComponentID voxelPosition,\n                                     const i32v3& centerPosition,\n                                     ui32 radius);\n    void removeChunkSphere(GameSystem* gameSystem, vecs::EntityID entity);\n    /// Frustum Component\n    vecs::ComponentID addFrustumComponent(GameSystem* gameSystem, vecs::EntityID entity,\n                                                  f32 fov, f32 aspectRatio, f32 znear, f32 zfar,\n                                                  vecs::ComponentID spacePosition = 0,\n                                                  vecs::ComponentID voxelPosition = 0,\n                                                  vecs::ComponentID head = 0);\n    void removeFrustumComponent(GameSystem* gameSystem, vecs::EntityID entity);\n    /// Head Component\n    vecs::ComponentID addHeadComponent(GameSystem* gameSystem, vecs::EntityID entity,\n                                               f64 neckLength);\n    void removeHeadComponent(GameSystem* gameSystem, vecs::EntityID entity);\n}\n\n#endif // GameSystemAssemblages_h__\n"
  },
  {
    "path": "SoA/GameSystemComponentBuilders.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameSystemComponentBuilders.h\"\n\n#include <Vorb/io/Keg.h>\n#include \"GameSystemComponents.h\"\n#include \"Frustum.h\"\n\nvoid AABBCollidableComponentBuilder::load(keg::ReadContext& context, keg::Node node) {\n    // Default value\n    component.box = f32v3(0.0f);\n    component.offset = f32v3(0.0f);\n\n    // Simple read\n    keg::parse((ui8*)&component, node, context, &KEG_GLOBAL_TYPE(AabbCollidableComponent));\n}\nvoid AABBCollidableComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).aabbCollidable.get(m_cID) = component;\n}\n\nvoid AABBCollidableComponentBuilder::postBuild(vecs::ECS& ecs, vecs::EntityID eID) {\n    GameSystem& gecs = static_cast<GameSystem&>(ecs);\n    auto& cmp = gecs.aabbCollidable.getFromEntity(eID);\n    cmp.physics = gecs.physics.getComponentID(eID);\n}\n\nvoid ParkourInputComponentBuilder::load(keg::ReadContext& context VORB_UNUSED, keg::Node node VORB_UNUSED) {\n    // Do nothing\n}\n\nvoid ParkourInputComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).parkourInput.get(m_cID) = component;\n}\n\nvoid ParkourInputComponentBuilder::postBuild(vecs::ECS& ecs, vecs::EntityID eID) {\n    GameSystem& gecs = static_cast<GameSystem&>(ecs);\n    auto& cmp = gecs.parkourInput.getFromEntity(eID);\n    cmp.physicsComponent = gecs.physics.getComponentID(eID);\n    cmp.attributeComponent = gecs.attributes.getComponentID(eID);\n    cmp.headComponent = gecs.head.getComponentID(eID);\n    cmp.aabbCollidable = gecs.aabbCollidable.getComponentID(eID);\n}\n\nvoid AttributeComponentBuilder::load(keg::ReadContext& context, keg::Node node) {\n    // Simple read\n    keg::parse((ui8*)&component, node, context, &KEG_GLOBAL_TYPE(AttributeComponent));\n}\n\nvoid AttributeComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).attributes.get(m_cID) = component;\n}\n\nvoid SpacePositionComponentBuilder::load(keg::ReadContext& context, keg::Node node) {\n    // Default value\n    component.position = f64v3(0.0f);\n    component.orientation = f64q(0.0, 0.0, 0.0, 1.0);\n    component.parentEntity = 0;\n    component.parentGravity = 0;\n    component.parentSphericalTerrain = 0;\n    \n    // Simple read\n    keg::parse((ui8*)&component, node, context, &KEG_GLOBAL_TYPE(SpacePositionComponent));\n}\nvoid SpacePositionComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).spacePosition.get(m_cID) = component;\n}\n\nvoid VoxelPositionComponentBuilder::load(keg::ReadContext& context, keg::Node node) {\n    // Default value\n    component.orientation = f64q(0.0, 0.0, 0.0, 1.0);\n    VoxelPosition3D pos;\n    pos.pos = f64v3(0.0);\n    pos.face = FACE_TOP;\n    component.gridPosition = pos;\n    component.parentVoxel = 0;\n\n    // Simple read\n    keg::parse((ui8*)&component, node, context, &KEG_GLOBAL_TYPE(VoxelPositionComponent));\n}\nvoid VoxelPositionComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).voxelPosition.get(m_cID) = component;\n}\n\nvoid PhysicsComponentBuilder::load(keg::ReadContext& context, keg::Node node) {\n    // Default value\n    component.velocity = f64v3(0.0);\n    component.mass = 1.0;\n    component.spacePosition = 0;\n    component.voxelPosition = 0;\n\n    // Simple read\n    keg::parse((ui8*)&component, node, context, &KEG_GLOBAL_TYPE(PhysicsComponent));\n}\nvoid PhysicsComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).physics.get(m_cID) = component;\n}\n\nvoid PhysicsComponentBuilder::postBuild(vecs::ECS& ecs, vecs::EntityID eID) {\n    GameSystem& gecs = static_cast<GameSystem&>(ecs);\n    auto& cmp = gecs.physics.getFromEntity(eID);\n    cmp.voxelPosition = gecs.voxelPosition.getComponentID(eID);\n}\n\nvoid FrustumComponentBuilder::load(keg::ReadContext& context, keg::Node node) {\n    // Default value\n    Frustum frustum;\n    frustum.setCamInternals(1.0f, 16.0f / 9.0f, 0.1f, 100.0f);\n    component.frustum = frustum;\n    component.spacePosition = 0;\n    component.voxelPosition = 0;\n    component.head = 0;\n    // Simple read\n    keg::parse((ui8*)&frustum, node, context, &KEG_GLOBAL_TYPE(FrustumComponent));\n    component.frustum = frustum;\n}\nvoid FrustumComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).frustum.get(m_cID) = component;\n}\n\nvoid HeadComponentBuilder::load(keg::ReadContext& context, keg::Node node) {\n    // Default value\n    component.neckLength = 0.0;\n    component.relativeOrientation = f64q(0.0, 0.0, 0.0, 1.0);\n    component.relativePosition = f64v3(0.0);\n\n    // Simple read\n    keg::parse((ui8*)&component, node, context, &KEG_GLOBAL_TYPE(FrustumComponent));\n}\nvoid HeadComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).head.get(m_cID) = component;\n}\nvoid HeadComponentBuilder::postBuild(vecs::ECS& ecs, vecs::EntityID eID) {\n    GameSystem& gecs = static_cast<GameSystem&>(ecs);\n    auto& cmp = gecs.head.getFromEntity(eID);\n    cmp.voxelPosition = gecs.voxelPosition.getComponentID(eID);\n}\n\nvoid InventoryComponentBuilder::load(keg::ReadContext& reader VORB_UNUSED, keg::Node node VORB_UNUSED) {\n    // TODO(Ben): Load another file using a file path\n}\n\nvoid InventoryComponentBuilder::build(vecs::ECS& ecs, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    ((GameSystem&)ecs).inventory.get(m_cID) = component;\n}"
  },
  {
    "path": "SoA/GameSystemComponentBuilders.h",
    "content": "#pragma once\n\n#ifndef GameSystemComponentBuilders_h__\n#define GameSystemComponentBuilders_h__\n\n#include <Vorb/ecs/ECS.h>\n\n#include \"GameSystem.h\"\n#include \"GameSystemComponents.h\"\n#include \"ECSTemplates.h\"\n\nclass AABBCollidableComponentBuilder: public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n    virtual void postBuild(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    AabbCollidableComponent component;\n};\n\nclass ParkourInputComponentBuilder: public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n    virtual void postBuild(vecs::ECS& ecs, vecs::EntityID eID) override;\n    ParkourInputComponent component;\n};\n\nclass AttributeComponentBuilder : public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    AttributeComponent component;\n};\n\n/* TODO(BEN): Implement these component builders\nclass FreeMoveInputComponentBuilder: public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    FreeMoveInputComponent component;\n};\n*/\n\nclass SpacePositionComponentBuilder: public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    SpacePositionComponent component;\n};\n\nclass VoxelPositionComponentBuilder: public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    VoxelPositionComponent component;\n};\n\nclass PhysicsComponentBuilder: public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n    virtual void postBuild(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    PhysicsComponent component;\n};\n\nclass FrustumComponentBuilder: public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    FrustumComponent component;\n};\n\nclass HeadComponentBuilder: public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n    virtual void postBuild(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    HeadComponent component;\n};\n\nclass InventoryComponentBuilder : public ECSComponentBuilder {\npublic:\n    virtual void load(keg::ReadContext& reader, keg::Node node) override;\n    virtual void build(vecs::ECS& ecs, vecs::EntityID eID) override;\n\n    InventoryComponent component;\n};\n\n#endif //GameSystemComponentBuilders_h__"
  },
  {
    "path": "SoA/GameSystemComponents.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameSystemComponents.h\"\n\nKEG_TYPE_DEF(AabbCollidableComponent, AabbCollidableComponent, kt) {\n    using namespace keg;\n    kt.addValue(\"box\", Value::basic(offsetOf(AabbCollidableComponent, box), BasicType::F32_V3));\n    kt.addValue(\"offset\", Value::basic(offsetOf(AabbCollidableComponent, offset), BasicType::F32_V3));\n}\n\nKEG_TYPE_DEF(AttributeComponent, AttributeComponent, kt) {\n    using namespace keg;\n    kt.addValue(\"strength\", Value::basic(offsetOf(AttributeComponent, strength), BasicType::F64));\n    kt.addValue(\"perception\", Value::basic(offsetOf(AttributeComponent, perception), BasicType::F64));\n    kt.addValue(\"endurance\", Value::basic(offsetOf(AttributeComponent, endurance), BasicType::F64));\n    kt.addValue(\"charisma\", Value::basic(offsetOf(AttributeComponent, charisma), BasicType::F64));\n    kt.addValue(\"intelligence\", Value::basic(offsetOf(AttributeComponent, intelligence), BasicType::F64));\n    kt.addValue(\"agility\", Value::basic(offsetOf(AttributeComponent, agility), BasicType::F64));\n    kt.addValue(\"height\", Value::basic(offsetOf(AttributeComponent, perception), BasicType::F64));\n}\n\n/*\n//TODO(BEN): Properly implement this\nKEG_TYPE_DEF(FreeMoveInputComponent, FreeMoveInputComponent, kt) {\n    using namespace keg;\n    kt.addValue(\"Speed\", Value::basic(offsetof(FreeMoveInputComponent, speed), BasicType::F32));\n}*/\n\nKEG_TYPE_DEF(SpacePositionComponent, SpacePositionComponent, kt) {\n    using namespace keg;\n    kt.addValue(\"position\", Value::basic(offsetof(SpacePositionComponent, position), BasicType::F64_V3));\n    kt.addValue(\"orientation\", Value::basic(offsetof(SpacePositionComponent, orientation), BasicType::F64_V4));\n}\n\nKEG_TYPE_DEF(VoxelPositionComponent, VoxelPositionComponent, kt) {\n    using namespace keg;\n    kt.addValue(\"orientation\", Value::basic(offsetof(VoxelPositionComponent, orientation), BasicType::F64_V4));\n    //kt.addValue(\"GridPosition\", Value::value(&VoxelPositionComponent::gridPosition));\n    kt.addValue(\"voxelPosition\", Value::basic(offsetof(VoxelPositionComponent, gridPosition), BasicType::F64_V3));\n    kt.addValue(\"worldCubeFace\", Value::basic(offsetof(VoxelPositionComponent, gridPosition) + offsetof(VoxelPosition3D, face), BasicType::ENUM));\n}\n\nKEG_TYPE_DEF(PhysicsComponent, PhysicsComponent, kt) {\n    using namespace keg;\n    kt.addValue(\"velocity\", Value::basic(offsetof(PhysicsComponent, velocity), BasicType::F64_V3));\n    kt.addValue(\"mass\", Value::basic(offsetof(PhysicsComponent, mass), BasicType::F32));\n}\n\nKEG_TYPE_DEF(FrustumComponent, FrustumComponent, kt) {\n    using namespace keg;\n    kt.addValue(\"fov\", Value::basic(0, BasicType::F32));\n    kt.addValue(\"aspectRatio\", Value::basic(sizeof(f32), BasicType::F32));\n    kt.addValue(\"zNear\", Value::basic(sizeof(f32) * 2, BasicType::F32));\n    kt.addValue(\"zFar\", Value::basic(sizeof(f32) *3, BasicType::F32));\n}\n\nKEG_TYPE_DEF(HeadComponent, HeadComponent, kt) {\n    using namespace keg;\n    kt.addValue(\"relOrientation\", Value::basic(offsetof(HeadComponent, relativeOrientation), BasicType::F64_V4));\n    kt.addValue(\"relPosition\", Value::basic(offsetof(HeadComponent, relativePosition), BasicType::F64_V3));\n    kt.addValue(\"neckLength\", Value::basic(offsetof(HeadComponent, neckLength), BasicType::F64));\n}\n\n"
  },
  {
    "path": "SoA/GameSystemComponents.h",
    "content": "///\n/// GameSystemComponents.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Components for game system\n///\n\n#pragma once\n\n#ifndef GameSystemComponents_h__\n#define GameSystemComponents_h__\n\n#include <Vorb/io/Keg.h>\n#include <Vorb/ecs/Entity.h>\n\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/ecs/ComponentTable.hpp>\n\n#include \"BlockData.h\"\n#include \"ChunkHandle.h\"\n#include \"Frustum.h\"\n#include \"VoxelCoordinateSpaces.h\"\n\nclass ChunkAccessor;\nclass ChunkGrid;\n\nstruct BlockCollisionData {\n    BlockCollisionData(BlockID id, ui16 index) : id(id), index(index), neighborCollideFlags(0) {}\n    BlockID id;\n    ui16 index;\n    union {\n        struct {\n            bool left : 1;\n            bool right : 1;\n            bool bottom : 1;\n            bool top : 1;\n            bool back : 1;\n            bool front : 1;\n        };\n        ui8 neighborCollideFlags;\n    };\n};\n\nstruct AabbCollidableComponent {\n    vecs::ComponentID physics;\n    std::map<ChunkID, std::vector<BlockCollisionData>> voxelCollisions;\n    // TODO(Ben): Entity-Entity collision\n    f32v3 box = f32v3(0.0f); ///< x, y, z widths in blocks\n    f32v3 offset = f32v3(0.0f); ///< x, y, z offsets in blocks\n};\ntypedef vecs::ComponentTable<AabbCollidableComponent> AABBCollidableComponentTable;\nKEG_TYPE_DECL(AabbCollidableComponent);\n\nstruct AttributeComponent {\n    f64 strength = 0.0;\n    f64 perception = 0.0;\n    f64 endurance = 0.0;\n    f64 charisma = 0.0;\n    f64 intelligence = 0.0;\n    f64 agility = 0.0;\n    f64 height = 4.0;\n};\ntypedef vecs::ComponentTable<AttributeComponent> AttributeComponentTable;\nKEG_TYPE_DECL(AttributeComponent);\n\nstruct ParkourInputComponent {\n    // Bitfield inputs\n    union {\n        struct {\n            bool moveForward : 1; ///< True when moving forward\n            bool moveBackward : 1; ///< True when moving backward\n            bool moveLeft : 1; ///< True when moving left\n            bool moveRight : 1; ///< True when moving right\n            bool jump : 1; ///< True when attempting to jump\n            bool crouch : 1; ///< True when attempting to crouch\n            bool parkour : 1; ///< True when parkouring\n            bool sprint : 1; ///< True when sprinting\n        };\n        ui8 moveFlags = 0;\n    };\n    vecs::ComponentID aabbCollidable;\n    vecs::ComponentID physicsComponent;\n    vecs::ComponentID attributeComponent;\n    vecs::ComponentID headComponent;\n};\ntypedef vecs::ComponentTable<ParkourInputComponent> ParkourInputComponentTable;\n\nstruct FreeMoveInputComponent {\n    // Bitfield inputs\n    union {\n        struct {\n            bool tryMoveForward : 1; ///< True when moving forward\n            bool tryMoveBackward : 1; ///< True when moving backward\n            bool tryMoveLeft : 1; ///< True when moving left\n            bool tryMoveRight : 1; ///< True when moving right\n            bool tryMoveUp : 1; ///< True when attempting to go up\n            bool tryMoveDown : 1; ///< True when attempting to go down\n            bool superSpeed : 1; ///< True when super speed is active\n            bool tryRollLeft : 1; ///< True when trying to roll left along cam Z\n            bool tryRollRight : 1; ///< True when trying to roll right along cam Z\n        };\n        ui16 moveFlags = 0;\n    };\n    vecs::ComponentID physicsComponent = 0;\n    float speed = 0.3f;\n};\ntypedef vecs::ComponentTable<FreeMoveInputComponent> FreeMoveInputComponentTable;\n//KEG_TYPE_DECL(FreeMoveInputComponent);\n\nstruct SpacePositionComponent {\n    f64v3 position = f64v3(0.0);\n    f64q orientation;\n    vecs::EntityID parentEntity = 0;\n    vecs::ComponentID parentGravity = 0; ///< Gravity component of parent system body\n    vecs::ComponentID parentSphericalTerrain = 0; ///< ST component of parent system body\n};\ntypedef vecs::ComponentTable<SpacePositionComponent> SpacePositionComponentTable;\nKEG_TYPE_DECL(SpacePositionComponent);\n\ntypedef f64v3 VoxelPosition;\n\nstruct VoxelPositionComponent {\n    f64q orientation;\n    f64v3 eulerAngles = f64v3(0.0); ///< Pitch, Yaw, Roll in radians.\n    VoxelPosition3D gridPosition;\n    vecs::ComponentID parentVoxel = 0;\n};\ntypedef vecs::ComponentTable<VoxelPositionComponent> VoxelPositionComponentTable;\nKEG_TYPE_DECL(VoxelPositionComponent);\n\nstruct ChunkSphereComponent {\n    vecs::ComponentID voxelPosition;\n\n    std::vector<ChunkHandle> activeChunks;\n\n    // TODO(Ben): Chunk position?\n    i32v3 offset = i32v3(0);\n    i32v3 centerPosition = i32v3(0);\n    ChunkGrid* chunkGrid = nullptr;\n    ChunkHandle* handleGrid = nullptr;\n    // For fast 1 chunk shift\n    std::vector<i32v3> acquireOffsets;\n    WorldCubeFace currentCubeFace = FACE_NONE;\n\n    i32 radius = 0;\n    i32 width = 0;\n    i32 layer = 0;\n    i32 size = 0;\n};\nclass ChunkSphereComponentTable : public vecs::ComponentTable<ChunkSphereComponent> {\npublic:\n    virtual void disposeComponent(vecs::ComponentID cID, vecs::EntityID eID VORB_MAYBE_UNUSED) override {\n        ChunkSphereComponent& cmp = _components[cID].second;\n        delete[] cmp.handleGrid;\n        cmp.handleGrid = nullptr;\n        cmp.chunkGrid = nullptr;\n    }\n};\n\nstruct PhysicsComponent {\n    f64v3 velocity = f64v3(0.0);\n    f32 mass;\n    vecs::ComponentID spacePosition = 0; ///< Optional\n    vecs::ComponentID voxelPosition = 0; ///< Optional\n};\ntypedef vecs::ComponentTable<PhysicsComponent> PhysicsComponentTable;\nKEG_TYPE_DECL(PhysicsComponent);\n\nstruct FrustumComponent {\n    Frustum frustum;\n    vecs::ComponentID spacePosition = 0; ///< Optional\n    vecs::ComponentID voxelPosition = 0; ///< Optional\n    vecs::ComponentID head = 0; ///< Optional\n};\ntypedef vecs::ComponentTable<FrustumComponent> FrustumComponentTable;\nKEG_TYPE_DECL(FrustumComponent);\n\nstruct HeadComponent {\n    vecs::ComponentID voxelPosition;\n    f64q relativeOrientation;\n    f64v3 eulerAngles = f64v3(0.0); ///< Pitch, Yaw, Roll in radians.\n    f64v3 angleToApply = f64v3(0.0);\n    f64v3 relativePosition = f64v3(0.0); ///< Position in voxel units relative to entity position\n    f64 neckLength = 0.0; ///< Neck length in voxel units\n};\ntypedef vecs::ComponentTable<HeadComponent> HeadComponentTable;\nKEG_TYPE_DECL(HeadComponent);\n\nstruct InventoryComponent {\n    std::vector<ItemStack> items; ///< Who needs fast lookups?\n};\ntypedef vecs::ComponentTable<InventoryComponent> InventoryComponentTable;\n\n#endif // GameSystemComponents_h__\n"
  },
  {
    "path": "SoA/GameSystemUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameSystemUpdater.h\"\n\n#include \"FreeMoveComponentUpdater.h\"\n#include \"GameSystem.h\"\n#include \"GameSystemAssemblages.h\"\n#include \"Inputs.h\"\n#include \"SoAState.h\"\n#include \"SpaceSystem.h\"\n#include \"SpaceSystemAssemblages.h\"\n#include \"TerrainPatch.h\"\n#include \"VoxelSpaceConversions.h\"\n#include \"VoxelSpaceUtils.h\"\n\n#include <Vorb/utils.h>\n\nGameSystemUpdater::GameSystemUpdater(OUT SoaState* soaState, InputMapper* inputMapper) :\n    m_soaState(soaState),\n    m_inputMapper(inputMapper) {\n}\n\nGameSystemUpdater::~GameSystemUpdater() {\n    \n}\n\nvoid GameSystemUpdater::update(OUT GameSystem* gameSystem, OUT SpaceSystem* spaceSystem, const SoaState* soaState VORB_MAYBE_UNUSED) {\n    // Update component tables\n    m_freeMoveUpdater.update(gameSystem, spaceSystem);\n    m_headUpdater.update(gameSystem);\n    m_aabbCollidableUpdater.update(gameSystem, spaceSystem);\n    m_parkourUpdater.update(gameSystem, spaceSystem, soaState);\n    m_physicsUpdater.update(gameSystem, spaceSystem);\n    m_collisionUpdater.update(gameSystem);\n    m_chunkSphereUpdater.update(gameSystem, spaceSystem);\n    m_frustumUpdater.update(gameSystem);\n}\n"
  },
  {
    "path": "SoA/GameSystemUpdater.h",
    "content": "///\n/// GameSystemUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates a GameSystem ECS\n///\n\n#pragma once\n\n#ifndef GameSystemUpdater_h__\n#define GameSystemUpdater_h__\n\n#include \"ChunkSphereComponentUpdater.h\"\n#include \"CollisionComponentUpdater.h\"\n#include \"FreeMoveComponentUpdater.h\"\n#include \"FrustumComponentUpdater.h\"\n#include \"InputMapper.h\"\n#include \"PhysicsComponentUpdater.h\"\n#include \"ParkourComponentUpdater.h\"\n#include \"AABBCollidableComponentUpdater.h\"\n#include \"HeadComponentUpdater.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include <Vorb/Event.hpp>\n#include <Vorb/VorbPreDecl.inl>\n\nstruct SoaState;\nclass SpaceSystem;\nstruct VoxelPositionComponent;\nstruct SoaState;\nDECL_VVOX(class VoxelPlanetMapData);\n\nclass GameSystemUpdater {\n    friend class GameSystemEvents;\npublic:\n    GameSystemUpdater(OUT SoaState* soaState, InputMapper* inputMapper);\n    ~GameSystemUpdater();\n    /// Updates the game system, and also updates voxel components for space system\n    /// planet transitions.\n    /// @param gameSystem: Game ECS\n    /// @param spaceSystem: Space ECS. Only SphericalVoxelComponents are modified.\n    void update(OUT GameSystem* gameSystem, OUT SpaceSystem* spaceSystem, const SoaState* soaState);\nprivate:\n\n    int m_frameCounter = 0; ///< Counts frames for updateVoxelPlanetTransitions updates\n\n    /// Updaters\n    PhysicsComponentUpdater m_physicsUpdater;\n    CollisionComponentUpdater m_collisionUpdater;\n    FreeMoveComponentUpdater m_freeMoveUpdater;\n    HeadComponentUpdater m_headUpdater;\n    AABBCollidableComponentUpdater m_aabbCollidableUpdater;\n    ParkourComponentUpdater m_parkourUpdater;\n    ChunkSphereComponentUpdater m_chunkSphereUpdater;\n    FrustumComponentUpdater m_frustumUpdater;\n\n    const SoaState* m_soaState = nullptr;\n    InputMapper* m_inputMapper = nullptr;\n};\n\n#endif // GameSystemUpdater_h__\n"
  },
  {
    "path": "SoA/GameplayLoadScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameplayLoadScreen.h\"\n\n#include \"App.h\"\n#include \"CommonState.h\"\n#include \"GamePlayScreen.h\"\n#include \"LoadTaskBlockData.h\"\n#include \"MainMenuScreen.h\"\n#include \"LoadTaskTextures.h\"\n#include \"SoaEngine.h\"\n#include \"SoAState.h\"\n\nGameplayLoadScreen::GameplayLoadScreen(const App* app, CommonState* state, MainMenuScreen* mainMenuScreen, GameplayScreen* gameplayScreen) :\nIAppScreen<App>(app),\nm_commonState(state),\nm_mainMenuScreen(mainMenuScreen),\nm_gameplayScreen(gameplayScreen) {\n    // Empty\n}\n\ni32 GameplayLoadScreen::getNextScreen() const {\n    return m_app->scrGamePlay->getIndex();\n}\n\ni32 GameplayLoadScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid GameplayLoadScreen::build() {\n    // Empty\n}\n\nvoid GameplayLoadScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid GameplayLoadScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    addLoadTask(\"BlockData\", new LoadTaskBlockData(&m_commonState->state->blocks,\n        &m_commonState->state->clientState.blockTextureLoader,\n        &m_commonState->loadContext));\n\n  //  addLoadTask(\"Textures\", new LoadTaskTextures);\n  //  m_monitor.setDep(\"Textures\", \"BlockData\");\n\n    m_gameplayScreen->m_renderer.init(m_commonState->window, m_commonState->loadContext, m_gameplayScreen, m_commonState);\n    m_gameplayScreen->m_renderer.hook();\n    m_commonState->loadContext.begin();\n    m_gameplayScreen->m_renderer.load(m_commonState->loadContext);\n\n    // Start the tasks\n    m_monitor.start();\n}\n\nvoid GameplayLoadScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    // Dispose our borrowed renderer\n    m_mainMenuScreen->m_renderer.dispose(m_commonState->loadContext);\n    // Disable main menu viewer\n    m_commonState->stages.spaceSystem.setSystemViewer(nullptr);\n    m_commonState->loadContext.end();\n}\n\nvoid GameplayLoadScreen::update(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    // Perform OpenGL calls\n    m_glrpc.processRequests(1);\n    m_commonState->loadContext.processRequests(1);\n    m_gameplayScreen->m_renderer.updateGL();\n\n    // Defer texture loading\n    static bool loadedTextures = false;\n    // End condition\n    if (!loadedTextures && m_gameplayScreen->m_renderer.isLoaded() && m_monitor.isTaskFinished(\"BlockData\")) {\n        // Post process the planets\n        for (auto& it : m_commonState->state->spaceSystem->sphericalTerrain) {\n            // auto& cmp = it.second;\n            SoaEngine::initVoxelGen(it.second.planetGenData, m_commonState->state->blocks);\n        }\n        m_commonState->state->clientState.blockTextures->update();\n        m_commonState->state->clientState.blockTextures->writeDebugAtlases();\n        //m_commonState->state->blockTextures->save(&m_commonState->state->blocks);\n        m_state = vui::ScreenState::CHANGE_NEXT;\n        loadedTextures = true;\n    }\n}\n\nvoid GameplayLoadScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_commonState->state->clientState.spaceCamera.updateProjection();\n    m_mainMenuScreen->m_renderer.render();\n}\n\nvoid GameplayLoadScreen::addLoadTask(const nString& name, ILoadTask* task) {\n    // Add the load task to the monitor\n    m_loadTasks.push_back(task);\n    m_monitor.addTask(name, m_loadTasks.back());\n}"
  },
  {
    "path": "SoA/GameplayLoadScreen.h",
    "content": "///\n/// GameplayLoadScreen.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 6 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Load screen for going into a game world\n///\n\n#pragma once\n\n#ifndef GameplayLoadScreen_h__\n#define GameplayLoadScreen_h__\n\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/Random.h>\n#include <Vorb/graphics/Texture.h>\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/ui/InputDispatcher.h>\n\n#include \"LoadMonitor.h\"\n\nclass App;\nclass MainMenuScreen;\nclass GameplayScreen;\nstruct CommonState;\n\n#define VORB_NUM_TEXTURES 7\n#define REGROWTH_NUM_TEXTURES 2\n\nclass GameplayLoadScreen : public vui::IAppScreen < App > {\npublic:\n    GameplayLoadScreen(const App* app, CommonState* state, MainMenuScreen* mainMenuScreen, GameplayScreen* gameplayScreen);\n\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\nprivate:\n    void addLoadTask(const nString& name, ILoadTask* task);\n    // Game state\n    CommonState* m_commonState = nullptr;\n    MainMenuScreen* m_mainMenuScreen = nullptr;\n    GameplayScreen* m_gameplayScreen = nullptr;\n\n    // Loading Tasks\n    LoadMonitor m_monitor;\n    std::vector<ILoadTask*> m_loadTasks;\n\n    vcore::RPCManager m_glrpc; ///< Handles cross-thread OpenGL calls\n};\n\n#endif // GameplayLoadScreen_h__"
  },
  {
    "path": "SoA/GameplayRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GameplayRenderer.h\"\n\n#include <Vorb/graphics/GLStates.h>\n#include <Vorb/ui/GameWindow.h>\n#include <Vorb/AssetLoader.h>\n\n#include \"ChunkMeshManager.h\"\n#include \"CommonState.h\"\n#include \"DebugRenderer.h\"\n#include \"Errors.h\"\n#include \"GameSystem.h\"\n#include \"GamePlayScreen.h\"\n#include \"MTRenderState.h\"\n#include \"PauseMenu.h\"\n#include \"SoAState.h\"\n#include \"SoaOptions.h\"\n#include \"SpaceSystem.h\"\n#include \"soaUtils.h\"\n\n#define DEVHUD_FONT_SIZE 32\n\nvoid GameplayRenderer::init(vui::GameWindow* window, StaticLoadContext& context,\n                            GameplayScreen* gameplayScreen, CommonState* commonState) {\n    m_window = window;\n    m_gameplayScreen = gameplayScreen;\n    m_commonState = commonState;\n    m_state = m_commonState->state;\n\n    // TODO(Ben): Dis is bad mkay\n    m_viewport = f32v4(0, 0, m_window->getWidth(), m_window->getHeight());\n    // Get window dimensions\n    f32v2 windowDims(m_viewport.z, m_viewport.w);\n\n    m_state->clientState.spaceCamera.setAspectRatio(windowDims.x / windowDims.y);\n    m_voxelCamera.setAspectRatio(windowDims.x / windowDims.y);\n\n    // Init Stages\n    stages.opaqueVoxel.init(window, context);\n    stages.cutoutVoxel.init(window, context);\n    stages.chunkGrid.init(window, context);\n    stages.transparentVoxel.init(window, context);\n    stages.liquidVoxel.init(window, context);\n    stages.devHud.init(window, context);\n    stages.pda.init(window, context);\n    stages.pauseMenu.init(window, context);\n    stages.nightVision.init(window, context);\n    stages.ssao.init(window, context);\n    stages.bloom.init(window, context);\n    stages.bloom.setParams();\n    stages.exposureCalc.init(window, context);\n\n    loadNightVision();\n\n    // No post-process effects to begin with\n    stages.bloom.setActive(true);\n    stages.nightVision.setActive(false);\n    stages.chunkGrid.setActive(true); // TODO(Ben): Temporary\n    //stages.chunkGrid.setActive(false);\n}\n\nvoid GameplayRenderer::setRenderState(const MTRenderState* renderState) {\n    m_renderState = renderState;\n}\n\nvoid GameplayRenderer::dispose(StaticLoadContext& context) {\n\n    // Kill the builder\n    if (m_loadThread) {\n        delete m_loadThread;\n        m_loadThread = nullptr;\n    }\n\n    stages.opaqueVoxel.dispose(context);\n    stages.cutoutVoxel.dispose(context);\n    stages.chunkGrid.dispose(context);\n    stages.transparentVoxel.dispose(context);\n    stages.liquidVoxel.dispose(context);\n    stages.devHud.dispose(context);\n    stages.pda.dispose(context);\n    stages.pauseMenu.dispose(context);\n    stages.nightVision.dispose(context);\n    stages.ssao.dispose(context);\n    stages.bloom.dispose(context);\n    stages.exposureCalc.dispose(context);\n\n    // dispose of persistent rendering resources\n    m_hdrTarget.dispose();\n    m_swapChain.dispose();\n}\n\nvoid GameplayRenderer::reloadShaders() {\n    // TODO(Ben): More\n    StaticLoadContext context;\n    m_chunkRenderer.dispose();\n    m_chunkRenderer.init();\n    m_commonState->stages.spaceSystem.reloadShaders();\n    stages.ssao.reloadShaders();\n}\n\nvoid GameplayRenderer::load(StaticLoadContext& context) {\n    m_isLoaded = false;\n\n    m_loadThread = new std::thread([&]() {\n        \n        vcore::GLRPC so[4];\n        size_t i = 0;\n        // Create the HDR target     \n        so[i].set([&](Sender, void*) {\n            Array<vg::GBufferAttachment> attachments;\n            vg::GBufferAttachment att[2];\n            // TODO(Ben): Don't think this is right.\n            // Color\n            att[0].format = vg::TextureInternalFormat::RGBA16F;\n            att[0].pixelFormat = vg::TextureFormat::RGBA;\n            att[0].pixelType = vg::TexturePixelType::UNSIGNED_BYTE;\n            att[0].number = 1;\n            // Normals\n            att[1].format = vg::TextureInternalFormat::RGBA16F;\n            att[1].pixelFormat = vg::TextureFormat::RGBA;\n            att[1].pixelType = vg::TexturePixelType::UNSIGNED_BYTE;\n            att[1].number = 2;\n            m_hdrTarget.setSize(m_window->getWidth(), m_window->getHeight());\n            m_hdrTarget.init(Array<vg::GBufferAttachment>(att, 2), vg::TextureInternalFormat::RGBA16F).initDepth();\n                        \n            if (soaOptions.get(OPT_MSAA).value.i > 0) {\n                glEnable(GL_MULTISAMPLE);\n            } else {\n                glDisable(GL_MULTISAMPLE);\n            }\n        });\n        m_glrpc.invoke(&so[i++], false);\n\n        // Create the swap chain for post process effects (HDR-capable)\n        so[i].set([&](Sender, void*) {\n            m_swapChain.init(m_window->getWidth(), m_window->getHeight(), vg::TextureInternalFormat::RGBA16F);\n        });\n        m_glrpc.invoke(&so[i++], false);\n\n        // Initialize the chunk renderer\n        so[i].set([&](Sender, void*) {\n            m_chunkRenderer.init();\n        });\n        m_glrpc.invoke(&so[i++], false);\n        // Wait for the last command to complete\n        so[i - 1].block();\n\n        // Load all the stages\n        stages.opaqueVoxel.load(context);\n        stages.cutoutVoxel.load(context);\n        stages.chunkGrid.load(context);\n        stages.transparentVoxel.load(context);\n        stages.liquidVoxel.load(context);\n        stages.devHud.load(context);\n        stages.pda.load(context);\n        stages.pauseMenu.load(context);\n        stages.nightVision.load(context);\n        stages.ssao.load(context);\n        stages.bloom.load(context);\n        stages.exposureCalc.load(context);\n        m_isLoaded = true;\n    });\n    m_loadThread->detach();\n}\n\nvoid GameplayRenderer::hook() {\n    // Note: Common stages are hooked in MainMenuRenderer, no need to re-hook\n    // Grab mesh manager handle\n    m_meshManager = m_state->clientState.chunkMeshManager;\n    stages.opaqueVoxel.hook(&m_chunkRenderer, &m_gameRenderParams);\n    stages.cutoutVoxel.hook(&m_chunkRenderer, &m_gameRenderParams);\n    stages.transparentVoxel.hook(&m_chunkRenderer, &m_gameRenderParams);\n    stages.liquidVoxel.hook(&m_chunkRenderer, &m_gameRenderParams);\n    stages.chunkGrid.hook(&m_gameRenderParams);\n \n    //stages.devHud.hook();\n    //stages.pda.hook();\n    stages.pauseMenu.hook(&m_gameplayScreen->m_pauseMenu);\n    stages.nightVision.hook(&m_commonState->quad);\n    stages.ssao.hook(&m_commonState->quad, m_window->getWidth(), m_window->getHeight());\n    stages.bloom.hook(&m_commonState->quad);\n    stages.exposureCalc.hook(&m_commonState->quad, &m_hdrTarget, &m_viewport, 1024);\n    m_commonState->stages.spaceSystem.setFarTerrainCamera(&m_voxelCamera);\n}\n\nvoid GameplayRenderer::updateGL() {\n    // TODO(Ben): Experiment with more requests\n    m_glrpc.processRequests(1);\n}\n\n\nvoid GameplayRenderer::render() {\n    // const GameSystem* gameSystem = m_state->gameSystem;\n    // const SpaceSystem* spaceSystem = m_state->spaceSystem;\n\n    updateCameras();\n    // Set up the gameRenderParams\n    const GameSystem* gs = m_state->gameSystem;\n\n    // Get the physics component\n    auto& phycmp = gs->physics.getFromEntity(m_state->clientState.playerEntity);\n    VoxelPosition3D pos;\n    if (phycmp.voxelPosition) {\n        pos = gs->voxelPosition.get(phycmp.voxelPosition).gridPosition;\n    }\n    // TODO(Ben): Is this causing the camera slide discrepancy? SHouldn't we use MTRenderState?\n    m_gameRenderParams.calculateParams(m_state->clientState.spaceCamera.getPosition(), &m_voxelCamera,\n                                       pos, 100, m_meshManager, &m_state->blocks, m_state->clientState.blockTextures, false);\n    // Bind the FBO\n    m_hdrTarget.useGeometry();\n  \n    glClear(GL_DEPTH_BUFFER_BIT);\n\n    // worldCamera passes\n    m_commonState->stages.skybox.render(&m_state->clientState.spaceCamera);\n\n    if (m_wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n    m_commonState->stages.spaceSystem.setShowAR(false);\n    m_commonState->stages.spaceSystem.setRenderState(m_renderState);\n    m_commonState->stages.spaceSystem.render(&m_state->clientState.spaceCamera);\n\n    if (m_renderState->hasVoxelPos) {\n        glClear(GL_DEPTH_BUFFER_BIT);\n        glEnable(GL_BLEND);\n        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n        stages.opaqueVoxel.render(&m_voxelCamera);\n        // _physicsBlockRenderStage->draw();\n        //  m_cutoutVoxelRenderStage->render();\n\n        // auto& voxcmp = gameSystem->voxelPosition.getFromEntity(m_state->clientState.playerEntity).parentVoxel;\n        stages.chunkGrid.setState(m_renderState);\n        stages.chunkGrid.render(&m_voxelCamera);\n        //  m_liquidVoxelRenderStage->render();\n        //  m_transparentVoxelRenderStage->render();\n\n        if (debugRenderer) {\n            debugRenderer->render(m_voxelCamera.getViewProjectionMatrix(),\n                                  m_voxelCamera.getPosition());\n        }\n    }\n    if (m_wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\n    // Check for face transition animation state\n    if (m_commonState->stages.spaceSystem.needsFaceTransitionAnimation) {\n        m_commonState->stages.spaceSystem.needsFaceTransitionAnimation = false;\n        m_increaseQuadAlpha = true;\n        m_coloredQuadAlpha = 0.0f;\n    }\n\n    stages.exposureCalc.render();\n    // Move exposure towards target\n    static const f32 EXPOSURE_STEP = 0.005f;\n    stepTowards(soaOptions.get(OPT_HDR_EXPOSURE).value.f, stages.exposureCalc.getExposure(), EXPOSURE_STEP);\n\n    // Post processing\n    m_swapChain.reset(0, m_hdrTarget.getGeometryID(), m_hdrTarget.getGeometryTexture(0), soaOptions.get(OPT_MSAA).value.i > 0, false);\n\n    // TODO(Ben): This is broken\n    if (stages.ssao.isActive()) {\n        stages.ssao.set(m_hdrTarget.getDepthTexture(), m_hdrTarget.getGeometryTexture(1), m_hdrTarget.getGeometryTexture(0), m_swapChain.getCurrent().getID());\n        stages.ssao.render(&m_voxelCamera);\n        m_swapChain.swap();\n        m_swapChain.use(0, false);\n    }\n\n    // last effect should not swap swapChain\n    if (stages.nightVision.isActive()) {\n        stages.nightVision.render();\n        m_swapChain.swap();\n        m_swapChain.use(0, false);\n    }\n\n    if (stages.bloom.isActive()) {\n        stages.bloom.render();\n\n        // Render star glow into same framebuffer for performance\n        glBlendFunc(GL_ONE, GL_ONE);\n        m_commonState->stages.spaceSystem.renderStarGlows(f32v3(1.0f));\n        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n        m_swapChain.swap();\n        m_swapChain.use(0, false);\n    } else {\n        glBlendFunc(GL_ONE, GL_ONE);\n        m_commonState->stages.spaceSystem.renderStarGlows(f32v3(1.0f));\n        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    }\n\n    // TODO: More Effects\n\n    // Draw to backbuffer for the last effect\n\n   // m_swapChain.bindPreviousTexture(0);\n    m_swapChain.unuse(m_window->getWidth(), m_window->getHeight());\n    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n    glDrawBuffer(GL_BACK);\n    // TODO(Ben): Do we really need to clear depth here...\n    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);\n    m_hdrTarget.bindDepthTexture(1);\n    m_commonState->stages.hdr.render();\n\n    // UI\n    // stages.devHud.render();\n    // stages.pda.render();\n    stages.pauseMenu.render();\n\n    // Cube face fade animation\n    if (m_increaseQuadAlpha) {\n        static const f32 FADE_INC = 0.07f;\n        m_coloredQuadAlpha += FADE_INC;\n        if (m_coloredQuadAlpha >= 3.5f) {\n            m_coloredQuadAlpha = 3.5f;\n            m_increaseQuadAlpha = false;\n        }\n      //  m_coloredQuadRenderer.draw(m_commonState->quad, f32v4(0.0, 0.0, 0.0, vmath::min(m_coloredQuadAlpha, 1.0f)));\n    } else if (m_coloredQuadAlpha > 0.0f) {\n        static const float FADE_DEC = 0.01f;  \n   //     m_coloredQuadRenderer.draw(m_commonState->quad, f32v4(0.0, 0.0, 0.0, vmath::min(m_coloredQuadAlpha, 1.0f)));\n        m_coloredQuadAlpha -= FADE_DEC;\n    }\n\n    if (m_shouldScreenshot) dumpScreenshot();\n\n    // Check for errors, just in case\n    checkGlError(\"GamePlayRenderer::render()\");\n}\n\nvoid GameplayRenderer::cycleDevHud(int offset VORB_UNUSED /* = 1 */) {\n   // stages.devHud.cycleMode(offset);\n}\n\nvoid GameplayRenderer::toggleNightVision() {\n    if (!stages.nightVision.isActive()) {\n        stages.nightVision.setActive(true);\n        m_nvIndex = 0;\n        stages.nightVision.setParams(m_nvParams[m_nvIndex]);\n    } else {\n        m_nvIndex++;\n        if (m_nvIndex >= m_nvParams.size()) {\n            stages.nightVision.setActive(false);\n        } else {\n            stages.nightVision.setParams(m_nvParams[m_nvIndex]);\n        }\n    }\n}\n\nvoid GameplayRenderer::loadNightVision() {\n    stages.nightVision.setActive(false);\n\n    // TODO(Ben): This yaml code is outdated\n    /*m_nvIndex = 0;\n    m_nvParams.clear();\n\n    vio::IOManager iom;\n    const cString nvData = iom.readFileToString(\"Data/NightVision.yml\");\n    if (nvData) {\n    Array<NightVisionRenderParams> arr;\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(nvData);\n    keg::Node node = context.reader.getFirst();\n    keg::Value v = keg::Value::array(0, keg::Value::custom(0, \"NightVisionRenderParams\", false));\n    keg::evalData((ui8*)&arr, &v, node, context);\n    for (size_t i = 0; i < arr.size(); i++) {\n    m_nvParams.push_back(arr[i]);\n    }\n    context.reader.load();\n    delete[] nvData;\n    }\n    if (m_nvParams.size() < 1) {\n    m_nvParams.push_back(NightVisionRenderParams::createDefault());\n    }*/\n}\n\nvoid GameplayRenderer::toggleChunkGrid() {\n    stages.chunkGrid.toggleActive();\n}\n\nvoid GameplayRenderer::updateCameras() {\n    const GameSystem* gs = m_state->gameSystem;\n    const SpaceSystem* ss = m_state->spaceSystem;\n\n    // Get the physics component\n    if (m_renderState->hasVoxelPos) {\n        m_voxelCamera.setFocalLength(0.0f);\n        m_voxelCamera.setClippingPlane(0.1f, 10000.0f);\n        m_voxelCamera.setPosition(m_renderState->playerPosition.gridPosition.pos + m_renderState->playerHead.relativePosition);\n        m_voxelCamera.setOrientation(m_renderState->playerPosition.orientation * m_renderState->playerHead.relativeOrientation);\n        m_voxelCamera.update();\n    }\n    // Player is relative to a planet, so add position if needed\n    CinematicCamera& spaceCamera = m_state->clientState.spaceCamera;\n    // TODO(Ben): Shouldn't be touching ECS here.\n    auto& phycmp = gs->physics.getFromEntity(m_state->clientState.playerEntity);\n    auto& spcmp = gs->spacePosition.get(phycmp.spacePosition);\n    if (spcmp.parentGravity) {\n        auto it = m_renderState->spaceBodyPositions.find(spcmp.parentEntity);\n        if (it != m_renderState->spaceBodyPositions.end()) {\n            spaceCamera.setPosition(m_renderState->spaceCameraPos + it->second);\n        } else {\n            auto& gcmp = ss->sphericalGravity.get(spcmp.parentGravity);\n            auto& npcmp = ss->namePosition.get(gcmp.namePositionComponent);\n            spaceCamera.setPosition(m_renderState->spaceCameraPos + npcmp.position);\n        }\n    } else {\n        spaceCamera.setPosition(m_renderState->spaceCameraPos);\n    }\n    spaceCamera.setIsDynamic(false);\n    spaceCamera.setFocalLength(0.0f);\n    spaceCamera.setClippingPlane(0.1f, 100000000000.0f);\n   \n    if (m_renderState->hasVoxelPos) {\n        spaceCamera.setOrientation(m_renderState->spaceCameraOrientation * m_renderState->playerHead.relativeOrientation);\n    } else {\n        spaceCamera.setOrientation(m_renderState->spaceCameraOrientation);\n    }\n    \n    spaceCamera.update();\n}\n\nvoid GameplayRenderer::dumpScreenshot() {\n    // Make screenshots directory\n    vio::IOManager().makeDirectory(\"Screenshots\");\n    // Take screenshot\n    dumpFramebufferImage(\"Screenshots/\", m_viewport);\n    m_shouldScreenshot = false;\n}\n"
  },
  {
    "path": "SoA/GameplayRenderer.h",
    "content": "/// \n///  GameplayRenderer.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the render pipeline for the\n///  GamePlayScreen.\n///\n#pragma once\n\n#ifndef GamePlayRenderer_h__\n#define GamePlayRenderer_h__\n\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GBuffer.h>\n#include <Vorb/graphics/RTSwapChain.hpp>\n#include <Vorb/vorb_rpc.h>\n\n#include \"Camera.h\"\n#include \"ChunkGridRenderStage.h\"\n#include \"ChunkRenderer.h\"\n#include \"ColoredFullQuadRenderer.h\"\n#include \"CutoutVoxelRenderStage.h\"\n#include \"DevHudRenderStage.h\"\n#include \"GameRenderParams.h\"\n#include \"HdrRenderStage.h\"\n#include \"LiquidVoxelRenderStage.h\"\n#include \"NightVisionRenderStage.h\"\n#include \"OpaqueVoxelRenderStage.h\"\n#include \"PauseMenuRenderStage.h\"\n#include \"PdaRenderStage.h\"\n#include \"PhysicsBlockRenderStage.h\"\n#include \"SkyboxRenderStage.h\"\n#include \"SpaceSystemRenderStage.h\"\n#include \"SsaoRenderStage.h\"\n#include \"TransparentVoxelRenderStage.h\"\n#include \"BloomRenderStage.h\"\n#include \"ExposureCalcRenderStage.h\"\n\n/// Forward declarations\nclass App;\nclass ChunkGridRenderStage;\nclass ChunkMeshManager;\nclass ChunkSlot;\nclass CutoutVoxelRenderStage;\nclass DevHudRenderStage;\nclass GameSystem;\nclass GameplayScreen;\nclass HdrRenderStage;\nclass LiquidVoxelRenderStage;\nclass MeshManager;\nclass NightVisionRenderStage;\nclass OpaqueVoxelRenderStage;\nclass PDA;\nclass PauseMenu;\nclass PauseMenuRenderStage;\nclass PdaRenderStage;\nclass PhysicsBlockRenderStage;\nclass Player;\nclass SkyboxRenderStage;\nclass SpaceSystem;\nclass SpaceSystemRenderStage;\nclass TransparentVoxelRenderStage;\nclass DebugRenderer;\nstruct MTRenderState;\nstruct CommonState;\nstruct SoaState;\n\nclass GameplayRenderer {\npublic:\n    /// Initializes the pipeline and passes dependencies\n    void init(vui::GameWindow* window, StaticLoadContext& context,\n              GameplayScreen* gameplayScreen, CommonState* commonState);\n\n    /// Call this every frame before render\n    void setRenderState(const MTRenderState* renderState);\n\n    void hook();\n\n    void load(StaticLoadContext& context);\n\n    void dispose(StaticLoadContext& context);\n\n    void reloadShaders();\n\n    void updateGL();\n\n    /// Renders the pipeline.\n    /// Make sure to call setRenderState first.\n    virtual void render();\n\n    /// Cycles the dev hud\n    /// @param offset: How much to offset the current mode\n    void cycleDevHud(int offset = 1);\n    /// Toggle the visibility of night vision\n    void toggleNightVision();\n    /// Load night vision data\n    void loadNightVision();\n    /// Toggle the visibility of chunkGrid\n    void toggleChunkGrid();\n\n    void toggleWireframe() { m_wireframe = !m_wireframe; }\n\n    void takeScreenshot() { m_shouldScreenshot = true; }\n\n    volatile const bool& isLoaded() const { return m_isLoaded; }\n\n    struct {\n        OpaqueVoxelRenderStage opaqueVoxel; ///< Renders opaque voxels\n        CutoutVoxelRenderStage cutoutVoxel; ///< Renders cutout voxels\n        ChunkGridRenderStage chunkGrid;\n        TransparentVoxelRenderStage transparentVoxel; ///< Renders transparent voxels\n        LiquidVoxelRenderStage liquidVoxel; ///< Renders liquid voxels\n        DevHudRenderStage devHud; ///< Renders the dev/debug HUD\n        PdaRenderStage pda; ///< Renders the PDA\n        PauseMenuRenderStage pauseMenu; ///< Renders the pause menu\n        NightVisionRenderStage nightVision; ///< Renders night vision\n        SSAORenderStage ssao; ///< Renders SSAO\n        BloomRenderStage bloom; ///< Renders Bloom effect\n        ExposureCalcRenderStage exposureCalc; ///< Calculate exposure\n    } stages;\n\n    DebugRenderer* debugRenderer = nullptr;\n\nprivate:\n    void updateCameras();\n    void dumpScreenshot();\n\n    Camera m_voxelCamera;\n    ChunkRenderer m_chunkRenderer;\n\n    ColoredFullQuadRenderer m_coloredQuadRenderer; ///< For rendering full screen colored quads\n\n    vg::GBuffer m_hdrTarget; ///< Framebuffer needed for the HDR rendering\n    vg::RTSwapChain<2> m_swapChain; ///< Swap chain of framebuffers used for post-processing\n\n    GameRenderParams m_gameRenderParams; ///< Shared rendering parameters for voxels\n    GameplayScreen* m_gameplayScreen = nullptr;\n\n    vui::GameWindow* m_window;\n    CommonState* m_commonState = nullptr;\n    SoaState* m_state = nullptr; ///< Game State\n    vcore::RPCManager m_glrpc;\n\n    std::thread* m_loadThread = nullptr;\n    volatile bool m_isLoaded = false;\n\n    // TODO: This is only for visualization purposes, must remove\n    std::vector<NightVisionRenderParams> m_nvParams; ///< Different night vision styles\n    ui32 m_nvIndex = 0;\n\n    ui32v4 m_viewport; ///< Viewport to draw to\n    ChunkMeshManager* m_meshManager; ///< Handle to the meshes\n    const MTRenderState* m_renderState = nullptr; ///< The current MT render state\n    float m_coloredQuadAlpha = 0.0f;\n    bool m_increaseQuadAlpha = false;\n    bool m_wireframe = false;\n    bool m_shouldScreenshot = false;\n};\n\n#endif // GamePlayRenderer_h__\n"
  },
  {
    "path": "SoA/GasGiantComponentRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GasGiantComponentRenderer.h\"\n\n#include \"ShaderLoader.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"RenderUtils.h\"\n\n#include <Vorb/MeshGenerators.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/RasterizerState.h>\n#include <Vorb/graphics/ShaderManager.h>\n\n#include <glm/gtx/transform.hpp>\n\n#define ICOSPHERE_SUBDIVISIONS 5\n\nGasGiantComponentRenderer::~GasGiantComponentRenderer() {\n    dispose();\n}\n\nvoid GasGiantComponentRenderer::initGL() {\n    if (!m_program.isCreated()) buildShader();\n    if (!m_vbo) buildMesh();\n}\n\nvoid GasGiantComponentRenderer::draw(const GasGiantComponent& ggCmp,\n                                     vecs::EntityID eid,\n                                     const f32m4& VP,\n                                     const f64q& orientation,\n                                     const f32v3& relCamPos,\n                                     const f32v3& lightDir,\n                                     const float zCoef,\n                                     const SpaceLightComponent* spCmp VORB_MAYBE_UNUSED,\n                                     const AtmosphereComponent* aCmp) {\n    // Get the render texture or load it if it hasn't been loaded\n    // TODO(Ben): Use a renderable component instead\n    VGTexture colorTexture = 0;\n    auto it = m_colorTextures.find(eid);\n    if (it == m_colorTextures.end()) {\n        vg::ScopedBitmapResource b(vg::ImageIO().load(ggCmp.colorMapPath));\n        if (b.data) {\n            colorTexture = vg::GpuMemory::uploadTexture(&b, vg::TexturePixelType::UNSIGNED_BYTE,\n                                                        vg::TextureTarget::TEXTURE_2D,\n                                                        &vg::SamplerState::LINEAR_CLAMP);\n        } else {\n            fprintf(stderr, \"Failed to load %s\\n\", ggCmp.colorMapPath.c_str());\n        }\n        m_colorTextures[eid] = colorTexture;\n    } else {\n        colorTexture = it->second;\n    }\n\n    m_program.use();\n    // For logarithmic Z buffer\n    glUniform1f(m_program.getUniform(\"unZCoef\"), zCoef);\n\n    // Convert f64q to f32q\n    f32q orientationF32;\n    orientationF32.x = (f32)orientation.x;\n    orientationF32.y = (f32)orientation.y;\n    orientationF32.z = (f32)orientation.z;\n    orientationF32.w = (f32)orientation.w;\n\n    // Get rotated light direction\n    const f32v3 rotLightDir = glm::inverse(orientationF32) * lightDir;\n\n    // Convert to matrix\n    f32m4 rotationMatrix = glm::toMat4(orientationF32);\n\n    // Set up matrix\n    f32m4 WVP(1.0);\n    setMatrixTranslation(WVP, -relCamPos);\n    WVP = VP * WVP * glm::scale(f32v3(ggCmp.radius, ggCmp.radius * (1.0 - ggCmp.oblateness), ggCmp.radius)) * rotationMatrix;\n\n    f32v3 rotRelCamPos = relCamPos * orientationF32;\n\n    // Upload uniforms\n    static f64 dt = 0.0;\n    dt += 0.00000001;\n    glUniform1f(unDT, (f32)dt);\n    glUniformMatrix4fv(unWVP, 1, GL_FALSE, &WVP[0][0]);\n    // Scattering uniforms\n    f32 camHeight = glm::length(relCamPos);\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, GL_FALSE, &WVP[0][0]);\n    glUniform3fv(m_program.getUniform(\"unCameraPos\"), 1, &rotRelCamPos[0]);\n    glUniform3fv(m_program.getUniform(\"unLightDirWorld\"), 1, &rotLightDir[0]);\n    glUniform3fv(m_program.getUniform(\"unInvWavelength\"), 1, &aCmp->invWavelength4[0]);\n    glUniform1f(m_program.getUniform(\"unCameraHeight2\"), camHeight * camHeight);\n    glUniform1f(m_program.getUniform(\"unOuterRadius\"), aCmp->radius);\n    glUniform1f(m_program.getUniform(\"unOuterRadius2\"), aCmp->radius * aCmp->radius);\n    glUniform1f(m_program.getUniform(\"unInnerRadius\"), aCmp->planetRadius);\n    glUniform1f(m_program.getUniform(\"unKrESun\"), aCmp->kr * aCmp->esun);\n    glUniform1f(m_program.getUniform(\"unKmESun\"), aCmp->km * aCmp->esun);\n    glUniform1f(m_program.getUniform(\"unKr4PI\"), (f32)(aCmp->kr * M_4_PI));\n    glUniform1f(m_program.getUniform(\"unKm4PI\"), (f32)(aCmp->km * M_4_PI));\n    float scale = 1.0f / (aCmp->radius - aCmp->planetRadius);\n    glUniform1f(m_program.getUniform(\"unScale\"), scale);\n    glUniform1f(m_program.getUniform(\"unScaleDepth\"), aCmp->scaleDepth);\n    glUniform1f(m_program.getUniform(\"unScaleOverScaleDepth\"), scale / aCmp->scaleDepth);\n    glUniform1i(m_program.getUniform(\"unNumSamples\"), 3);\n    glUniform1f(m_program.getUniform(\"unNumSamplesF\"), 3.0f);\n    glUniform1f(m_program.getUniform(\"unG\"), aCmp->g);\n    glUniform1f(m_program.getUniform(\"unG2\"), aCmp->g * aCmp->g);\n   \n    // Bind VAO\n    glBindVertexArray(m_vao);\n   \n    // Bind lookup texture\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D, colorTexture);\n\n    glDrawElements(GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, 0);\n\n    glBindVertexArray(0);\n    m_program.unuse();\n}\n\nvoid GasGiantComponentRenderer::dispose() {\n    if (m_program.isCreated()) m_program.dispose();\n    if (m_vbo) {\n        vg::GpuMemory::freeBuffer(m_vbo);\n        m_vbo = 0;\n    }\n    if (m_ibo) {\n        vg::GpuMemory::freeBuffer(m_ibo);\n        m_ibo = 0;\n    }\n    if (m_vao) {\n        glDeleteVertexArrays(1, &m_vao);\n        m_vao = 0;\n    }\n}\n\nvoid GasGiantComponentRenderer::buildShader() {\n    m_program = ShaderLoader::createProgramFromFile(\"Shaders/GasGiant/GasGiant.vert\",\n                                                    \"Shaders/GasGiant/GasGiant.frag\");\n    m_program.use();\n    glUniform1i(m_program.getUniform(\"unColorBandLookup\"), 0);\n    unWVP = m_program.getUniform(\"unWVP\");\n    unDT = m_program.getUniform(\"unDT\");\n    m_program.unuse();\n}\n\nvoid GasGiantComponentRenderer::buildMesh() {\n    std::vector<ui32> indices;\n    std::vector<f32v3> positions;\n\n    // TODO(Ben): Optimize with LOD for far viewing\n    vmesh::generateIcosphereMesh(ICOSPHERE_SUBDIVISIONS, indices, positions);\n    m_numIndices = indices.size();\n\n    std::vector<GasGiantVertex> vertices(positions.size());\n    for (size_t i = 0; i < positions.size(); i++) {\n        vertices[i].position = positions[i];\n        vertices[i].texCoord = (positions[i].y + 1.0f) / 2.0f;\n    }\n\n    glGenVertexArrays(1, &m_vao);\n    glBindVertexArray(m_vao);\n\n    vg::GpuMemory::createBuffer(m_vbo);\n    vg::GpuMemory::createBuffer(m_ibo);\n\n    vg::GpuMemory::bindBuffer(m_vbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_vbo, vg::BufferTarget::ARRAY_BUFFER, vertices.size() * sizeof(GasGiantVertex),\n                                    vertices.data(), vg::BufferUsageHint::STATIC_DRAW);\n\n    vg::GpuMemory::bindBuffer(m_ibo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_ibo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(ui32),\n                                    indices.data(), vg::BufferUsageHint::STATIC_DRAW);\n\n    m_program.enableVertexAttribArrays();\n    glVertexAttribPointer(m_program.getAttribute(\"vPosition\"), 3, GL_FLOAT, GL_FALSE, sizeof(GasGiantVertex), offsetptr(GasGiantVertex, position));\n    glVertexAttribPointer(m_program.getAttribute(\"vTexCoord\"), 1, GL_FLOAT, GL_FALSE, sizeof(GasGiantVertex), offsetptr(GasGiantVertex, texCoord));\n\n    glBindVertexArray(0);\n}\n"
  },
  {
    "path": "SoA/GasGiantComponentRenderer.h",
    "content": "///\n/// GasGiantComponentRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 3 Apr 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renders gas giant components\n///\n\n#pragma once\n\n#ifndef GasGiantComponentRenderer_h__\n#define GasGiantComponentRenderer_h__\n\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/ecs/ComponentTable.hpp>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/graphics/GLProgram.h>\n\nstruct GasGiantComponent;\nstruct SpaceLightComponent;\nstruct AtmosphereComponent;\n\nstruct GasGiantVertex {\n    f32v3 position;\n    f32 texCoord;\n};\n\nclass GasGiantComponentRenderer {\npublic:\n    ~GasGiantComponentRenderer();\n\n    void initGL();\n\n    void draw(const GasGiantComponent& ggCmp,\n              vecs::EntityID eid,\n              const f32m4& VP,\n              const f64q& orientation,\n              const f32v3& relCamPos,\n              const f32v3& lightDir,\n              const float zCoef,\n              const SpaceLightComponent* spCmp,\n              const AtmosphereComponent* aCmp);\n    void dispose();\nprivate:\n    void buildShader();\n    void buildMesh();\n\n    vg::GLProgram m_program;\n    VGBuffer m_vbo = 0;\n    VGIndexBuffer m_ibo = 0;\n    VGVertexArray m_vao = 0;\n    int m_numIndices = 0;\n\n    // TODO(Ben): Use a renderable component instead\n    std::unordered_map<vecs::EntityID, VGTexture> m_colorTextures;\n\n    // TODO(Ben): UBO\n    VGUniform unWVP;\n    VGUniform unDT;\n};\n\n#endif // GasGiantComponentRenderer_h__\n\n"
  },
  {
    "path": "SoA/GenerateTask.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GenerateTask.h\"\n\n#include \"Chunk.h\"\n#include \"ChunkGenerator.h\"\n#include \"ChunkGrid.h\"\n#include \"FloraGenerator.h\"\n\nvoid GenerateTask::execute(WorkerData* workerData) {\n    Chunk& chunk = query->chunk;\n\n    // Check if this is a heightmap gen\n    if (chunk.gridData->isLoading) {\n        chunkGenerator->m_proceduralGenerator.generateHeightmap(&chunk, heightData);\n    } else { // Its a chunk gen\n\n        switch (query->genLevel) {\n            case ChunkGenLevel::GEN_DONE:\n            case ChunkGenLevel::GEN_TERRAIN:\n                chunkGenerator->m_proceduralGenerator.generateChunk(&chunk, heightData);\n                chunk.genLevel = GEN_TERRAIN;\n                // TODO(Ben): Not lazy load.\n                if (!workerData->floraGenerator) {\n                    workerData->floraGenerator = new FloraGenerator;\n                }\n                generateFlora(workerData, chunk);\n                chunk.genLevel = ChunkGenLevel::GEN_DONE;\n                break;\n            case ChunkGenLevel::GEN_FLORA:\n                chunk.genLevel = ChunkGenLevel::GEN_DONE;\n                break;\n            case ChunkGenLevel::GEN_SCRIPT:\n                chunk.genLevel = ChunkGenLevel::GEN_DONE;\n                break;\n            default:\n                break;\n        }\n        query->m_isFinished = true;\n        query->m_cond.notify_one();\n        // TODO(Ben): Not true for all gen?\n        chunk.isAccessible = true;\n    }\n    chunkGenerator->finishQuery(query);\n}\n\nstruct ChunkFloraArrays {\n    std::vector<VoxelToPlace> fNodes;\n    std::vector<VoxelToPlace> wNodes;\n};\n\nvoid GenerateTask::generateFlora(WorkerData* workerData, Chunk& chunk) {\n    std::vector<FloraNode> fNodes, wNodes;\n    workerData->floraGenerator->generateChunkFlora(&chunk, heightData, fNodes, wNodes);\n\n\n    // Sort based on chunk to minimize locking\n    std::map<ChunkID, ChunkFloraArrays> chunkMap;\n\n    // Add all nodes\n    // TODO(Ben): There should be a way to approximate size needs or use map on generator side.\n    for (auto& it : fNodes) {\n        ChunkID id(chunk.getID());\n        id.x += FloraGenerator::getChunkXOffset(it.chunkOffset);\n        id.y += FloraGenerator::getChunkYOffset(it.chunkOffset);\n        id.z += FloraGenerator::getChunkZOffset(it.chunkOffset);\n        chunkMap[id].fNodes.emplace_back(it.blockID, it.blockIndex);\n    }\n    for (auto& it : wNodes) {\n        ChunkID id(chunk.getID());\n        id.x += FloraGenerator::getChunkXOffset(it.chunkOffset);\n        id.y += FloraGenerator::getChunkYOffset(it.chunkOffset);\n        id.z += FloraGenerator::getChunkZOffset(it.chunkOffset);\n\n        chunkMap[id].wNodes.emplace_back(it.blockID, it.blockIndex);\n    }\n\n    // Traverse chunks\n    for (auto& it : chunkMap) {\n        ChunkHandle h = query->grid->accessor.acquire(it.first);\n        // TODO(Ben): Handle other case\n        if (h->genLevel >= GEN_TERRAIN) {\n            {\n                std::lock_guard<std::mutex> l(h->dataMutex);\n                for (auto& node : it.second.wNodes) {\n                    h->blocks.set(node.blockIndex, node.blockID);\n                }\n                for (auto& node : it.second.fNodes) {\n                    if (h->blocks.get(node.blockIndex) == 0) {\n                        h->blocks.set(node.blockIndex, node.blockID);\n                    }\n                }\n            }\n\n            if (h->genLevel == GEN_DONE) h->DataChange(h);\n        } else {\n            query->grid->nodeSetter.setNodes(h, GEN_TERRAIN, it.second.wNodes, it.second.fNodes);\n        }\n        h.release();\n    }\n\n    std::vector<ui16>().swap(chunk.floraToGenerate);\n}"
  },
  {
    "path": "SoA/GenerateTask.h",
    "content": "///\n/// GenerateTask.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Implements the generate task for SoA chunk generation\n///\n\n#pragma once\n\n#ifndef LoadTask_h__\n#define LoadTask_h__\n\n#include <Vorb/IThreadPoolTask.h>\n\n#include \"VoxPool.h\"\n\nclass Chunk;\nclass ChunkGenerator;\nclass ChunkQuery;\nstruct PlanetHeightData;\n\n#define GENERATE_TASK_ID 1\n\n// Represents A Chunk Load Task\n\nclass GenerateTask : public vcore::IThreadPoolTask<WorkerData> {\npublic:\n    GenerateTask() : vcore::IThreadPoolTask<WorkerData>(GENERATE_TASK_ID) {}\n\n    void init(ChunkQuery *query,\n              PlanetHeightData* heightData,\n              ChunkGenerator* chunkGenerator) {\n        this->query = query;\n        this->heightData = heightData;\n        this->chunkGenerator = chunkGenerator;\n    }\n\n    void execute(WorkerData* workerData) override;\n\n    // Chunk To Be Loaded\n    ChunkQuery* query;\n    ChunkGenerator* chunkGenerator; ///< send finished query here\n\n    // Loading Information\n    PlanetHeightData* heightData;\n\nprivate:\n    void generateFlora(WorkerData* workerData, Chunk& chunk);\n};\n\n#endif // LoadTask_h__\n"
  },
  {
    "path": "SoA/GeometrySorter.cpp",
    "content": "#include \"stdafx.h\"\n#include \"GeometrySorter.h\"\n\n#include \"soaUtils.h\"\n#include <Vorb/utils.h>\n\n#include \"ChunkRenderer.h\"\n\nstd::vector <Distanceclass> GeometrySorter::_distBuffer;\n\ni32 convertData(Distanceclass* data) {\n    return data->distance;\n}\n\nbool comparator(const Distanceclass& i, const Distanceclass& j) { \n    return (i.distance > j.distance); \n}\n\nvoid GeometrySorter::sortTransparentBlocks(ChunkMesh* cm, const i32v3& cameraPos) {\n\n    _distBuffer.resize(cm->transQuadPositions.size());\n\n    for (size_t i = 0; i < cm->transQuadPositions.size(); i++) {\n        _distBuffer[i].quadIndex = i; \n        //We multiply by 2 because we need twice the precision of integers per block\n        //we subtract by 1 in order to ensure that the camera position is centered on a block\n        _distBuffer[i].distance = selfDot(((i32v3(cm->position) - cameraPos) << 1) - 1 + i32v3(cm->transQuadPositions[i]));\n    }\n\n   // radixSort<Distanceclass, 8>(&(_distBuffer[0]), _distBuffer.size(), convertData, 31);\n    std::sort(_distBuffer.begin(), _distBuffer.end(), comparator);\n\n    int startIndex;\n    int j = 0;\n    for (size_t i = 0; i < _distBuffer.size(); i++) {\n        startIndex = _distBuffer[i].quadIndex * 4;\n        cm->transQuadIndices[j] = startIndex;\n        cm->transQuadIndices[j + 1] = startIndex + 1;\n        cm->transQuadIndices[j + 2] = startIndex + 2;\n        cm->transQuadIndices[j + 3] = startIndex + 2;\n        cm->transQuadIndices[j + 4] = startIndex + 3;\n        cm->transQuadIndices[j + 5] = startIndex;\n        j += 6;\n    }\n}"
  },
  {
    "path": "SoA/GeometrySorter.h",
    "content": "#pragma once\n\n#include <vector>\n#include \"Vorb/types.h\"\n\nclass ChunkMesh;\n\nclass Distanceclass {\npublic:\n    i32 quadIndex;\n    i32 distance;\n};\n\nclass GeometrySorter {\npublic:\n    static void sortTransparentBlocks(ChunkMesh* cm, const i32v3& cameraPos);\n\nprivate:\n\n\n    static std::vector <Distanceclass> _distBuffer;\n};"
  },
  {
    "path": "SoA/HdrRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"HdrRenderStage.h\"\n\n#include <Vorb/graphics/ShaderManager.h>\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkRenderer.h\"\n#include \"GameRenderParams.h\"\n#include \"SoaOptions.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n\nvoid HdrRenderStage::hook(vg::FullQuadVBO* quad) {\n    m_quad = quad;\n}\n\nvoid HdrRenderStage::dispose(StaticLoadContext& context VORB_MAYBE_UNUSED) {\n    if (m_programBlur.isCreated()) m_programBlur.dispose();\n    if (m_programDoFBlur.isCreated()) m_programDoFBlur.dispose();\n}\n\nvoid HdrRenderStage::render(const Camera* camera /*= nullptr*/) {\n    f32m4 oldVP = m_oldVP;\n    f32m4 vp;\n    if (camera) {\n        vp = camera->getProjectionMatrix() * camera->getViewMatrix();\n        m_oldVP = vp;\n    }\n    vg::GLProgram* program;\n    \n    if (soaOptions.get(OPT_MOTION_BLUR).value.i > 0) {\n        if (!m_programBlur.isCreated()) {\n            m_programBlur = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\",\n                                                                       \"Shaders/PostProcessing/MotionBlur.frag\",\n                                                                       nullptr, \"#define MOTION_BLUR\\n\");\n        }\n        program = &m_programBlur;\n    } else {\n        if (!m_program.isCreated()) {\n            m_program = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\",\n                                                                 \"Shaders/PostProcessing/MotionBlur.frag\");\n        }\n        program = &m_program;\n    }\n\n    // TODO(Ben): DOF shader?\n    //program = /*graphicsOptions.depthOfField == 1 ? _glProgramDoFBlur :*/ _glProgram;\n\n    program->use();\n    program->enableVertexAttribArrays();\n\n    glUniform1i(program->getUniform(\"unTex\"), 0);\n    glUniform1f(program->getUniform(\"unGamma\"), 1.0f / soaOptions.get(OPT_GAMMA).value.f);\n    glUniform1f(program->getUniform(\"unExposure\"), soaOptions.get(OPT_HDR_EXPOSURE).value.f);\n    if (soaOptions.get(OPT_MOTION_BLUR).value.i > 0) {\n        f32m4 newInverseVP = glm::inverse(vp);\n        glUniform1i(program->getUniform(\"unTexDepth\"), 1);\n        glUniformMatrix4fv(program->getUniform(\"unVPPrev\"), 1, GL_FALSE, &oldVP[0][0]);\n        glUniformMatrix4fv(program->getUniform(\"unVPInv\"), 1, GL_FALSE, &newInverseVP[0][0]);\n        glUniform1i(program->getUniform(\"unNumSamples\"), soaOptions.get(OPT_MOTION_BLUR).value.i);\n        glUniform1f(program->getUniform(\"unBlurIntensity\"), 0.5f);\n    }\n    //if (graphicsOptions.depthOfField > 0) {\n    //    glUniform1f(_glprogram->getUniform(\"unFocalLen\"), 70.0f);\n    //    glUniform1f(_glprogram->getUniform(\"unZfocus\"), 0.96f); // [0, 1]\n    //}\n\n    glDisable(GL_DEPTH_TEST);\n    m_quad->draw();\n    glEnable(GL_DEPTH_TEST);\n\n    program->disableVertexAttribArrays();\n    program->unuse();\n}\n"
  },
  {
    "path": "SoA/HdrRenderStage.h",
    "content": "/// \n///  HdrRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the HDR render stage, which\n///  does HDR post processing.\n///\n\n#pragma once\n\n#ifndef HdrRenderStage_h__\n#define HdrRenderStage_h__\n\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/GLProgram.h>\n\n#include \"IRenderStage.h\"\n\nclass Camera;\n\nclass HdrRenderStage : public IRenderStage {\npublic:\n    /// @param quad: Quad used for rendering to screen\n    void hook(vg::FullQuadVBO* quad);\n\n    /// Disposes and deletes the shader and turns off visibility\n    /// If stage does lazy init, shader will reload at next draw\n    virtual void dispose(StaticLoadContext& context) override;\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera = nullptr) override;\nprivate:\n    vg::GLProgram m_program;\n    vg::GLProgram m_programBlur; ///< Motion blur enabled\n    vg::GLProgram m_programDoFBlur; ///< Motion blur and DoF enabled\n    vg::FullQuadVBO* m_quad = nullptr; ///< For use in processing through data\n    f32m4 m_oldVP = f32m4(1.0f); ///< ViewProjection of previous frame\n};\n\n#endif // HdrRenderStage_h__"
  },
  {
    "path": "SoA/HeadComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"HeadComponentUpdater.h\"\n#include \"Constants.h\"\n\n#include \"GameSystem.h\"\n#include \"soaUtils.h\"\n\nvoid HeadComponentUpdater::update(GameSystem* gameSystem VORB_UNUSED) {\n    // Empty for now\n}\n\nvoid HeadComponentUpdater::rotateFromMouse(GameSystem* gameSystem, vecs::ComponentID cmpID, float dx, float dy, float speed) {\n    // Seems like a race condition\n    auto& cmp = gameSystem->head.get(cmpID);\n\n    // Pitch\n    cmp.eulerAngles.x += dy * speed;\n    cmp.eulerAngles.x = vmath::clamp(cmp.eulerAngles.x, -M_PI_2, M_PI_2);\n    // Yaw\n    cmp.eulerAngles.y += dx * speed;\n\n    // Check if we need to rotate the body\n    if (cmp.eulerAngles.y < -M_PI_2) {\n        auto& vpCmp = gameSystem->voxelPosition.get(cmp.voxelPosition);\n        vpCmp.eulerAngles.y += cmp.eulerAngles.y + M_PI_2;\n        cmp.eulerAngles.y = -M_PI_2;\n    } else if (cmp.eulerAngles.y > M_PI_2) {\n        auto& vpCmp = gameSystem->voxelPosition.get(cmp.voxelPosition);\n        vpCmp.eulerAngles.y += cmp.eulerAngles.y - M_PI_2;\n        cmp.eulerAngles.y = M_PI_2;\n    }\n\n    cmp.relativeOrientation = f64q(cmp.eulerAngles);\n}"
  },
  {
    "path": "SoA/HeadComponentUpdater.h",
    "content": "//\n// HeadComponentUpdater.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 15 Aug 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Updater for Head Components.\n//\n\n#pragma once\n\n#ifndef HeadComponentUpdater_h__\n#define HeadComponentUpdater_h__\n\n#include <Vorb/ecs/Entity.h>\n\nclass GameSystem;\nclass HeadComponentUpdater {\npublic:\n    void update(GameSystem* gameSystem);\n    static void rotateFromMouse(GameSystem* gameSystem, vecs::ComponentID cmpID, float dx, float dy, float speed);\n};\n\n#endif // HeadComponentUpdater_h__\n"
  },
  {
    "path": "SoA/IRenderStage.h",
    "content": "/// \n///  IRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Ben Arnold on 28 Oct 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file provides an abstract interface for a render \n///  stage.\n///\n\n#pragma once\n\n#ifndef IRenderStage_h_\n#define IRenderStage_h_\n\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/VorbPreDecl.inl>\n\nclass Camera;\nclass StaticLoadContext;\nstruct SoaState;\nDECL_VUI(class GameWindow)\n\nclass IRenderStage {\npublic:\n    /*! @brief Simple fast initialization performed in main game loop.\n    *\n    * Should increment the amount of expected work to be done in the context.\n    * Only simple initialization logic should be performed here\n    *\n    * @param context: Common loading context.\n    */\n    virtual void init(vui::GameWindow* window, StaticLoadContext& context VORB_MAYBE_UNUSED) { m_window = window; }\n\n    /*! @brief Invokes core loading logic\n    *\n    * The loading logic of this render stage is invoked on a separate thread. The work\n    * completed should be updated on the context as it is finished.\n    *\n    * @param context: Common loading context that holds an RPCManager\n    */\n    virtual void load(StaticLoadContext& context VORB_MAYBE_UNUSED) {}\n\n    /*! @brief Destroys all resources held by this render stage.\n    *\n    * Called within the game loop, the destruction should be fast and minimal.\n    *\n    * @param context: Common loading context.\n    */\n    virtual void dispose(StaticLoadContext& context VORB_MAYBE_UNUSED) {}\n\n    /*! @brief Implementation-defined rendering logic.\n    *\n    * The rendering code should only concern itself with setting up the shaders, geometry\n    * and sending the draw calls. Other state (like draw destinations) are handled externally.\n    *\n    * @param camera: Viewpoint for the rendering\n    */\n    virtual void render(const Camera* camera) = 0;\n\n    virtual const volatile bool& isBuilt() const { return m_built; }\n\n    /// Sets the visibility of the stage\n    /// @param isVisible: The visibility\n    virtual void setActive(bool isVisible) { m_isActive = isVisible; }\n\n    /// Toggles the isVisible field\n    virtual void toggleActive() { m_isActive = !m_isActive; }\n\n    /// Check if the stage is visible\n    virtual const bool& isActive() const { return m_isActive; }\nprotected:\n    vui::GameWindow* m_window;\n    bool m_isActive = true; ///< Determines if the stage should be rendered\n    volatile bool m_built = false;\n};\n\n#endif // IRenderStage_h_\n"
  },
  {
    "path": "SoA/ImageAssetLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ImageAssetLoader.h\"\n\n#include <Vorb/graphics/GLStates.h>\n\nvoid vcore::AssetBuilder<ImageAsset>::create(const vpath& p, OUT ImageAsset* asset, vcore::RPCManager& rpc) {\n    vg::BitmapResource bmp = m_imageLoader.load(p, vg::ImageIOFormat::RGBA_UI8);\n    if (!bmp.data) return;\n\n    asset->texture.width = bmp.width;\n    asset->texture.height = bmp.height;\n\n    GLRPC so(asset);\n    so.set([bmp](Sender, void* userData) {\n        ImageAsset* asset = (ImageAsset*)userData;\n\n        // Create the texture\n        glGenTextures(1, &asset->texture.id);\n        glBindTexture(GL_TEXTURE_2D, asset->texture.id);\n        vg::SamplerState::LINEAR_WRAP.set(GL_TEXTURE_2D);\n        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, asset->texture.width, asset->texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bmp.data);\n        glBindTexture(GL_TEXTURE_2D, 0);\n    });\n    rpc.invoke(&so);\n\n    vg::ImageIO::free(bmp);\n}\n\nvoid vcore::AssetBuilder<ImageAsset>::destroy(ImageAsset* asset) {\n    glDeleteTextures(1, &asset->texture.id);\n}\n"
  },
  {
    "path": "SoA/ImageAssetLoader.h",
    "content": "///\n/// ImageAssetLoader.h\n///\n/// Created by Cristian Zaloj on 13 Feb 2015\n///\n/// Summary:\n/// Loads image assets.\n///\n\n#pragma once\n\n#ifndef ImageAssetLoader_h__\n#define ImageAssetLoader_h__\n\n#include <Vorb/AssetLoader.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/graphics/Texture.h>\n\nclass ImageAsset : public vcore::Asset {\npublic:\n    vg::Texture texture;\n};\n\ntemplate<>\nstruct vcore::AssetBuilder<ImageAsset> {\npublic:\n    void create(const vpath& p, OUT ImageAsset* asset, vcore::RPCManager& rpc);\n    void destroy(ImageAsset* asset);\nprivate:\n    vg::ImageIO m_imageLoader;\n};\n\nCONTEXTUAL_ASSET_LOADER(ImageAssetLoader, ImageAsset);\n\n#endif // ImageAssetLoader_h__\n"
  },
  {
    "path": "SoA/IniParser.cpp",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <sys/stat.h>\n#include <memory>\n\n//stupid Windows SDK mucking up the namespace\n#if defined(_WIN32) || defined(_WIN64)\n#define UNKNOWN WINDOWS_UNKNOWN\n#define CHAR WINDOWS_CHAR\n#define SHORT WINDOWS_SHORT\n#define INT WINDOWS_INT\n#define LONG WINDOWS_LONG\n#define FLOAT WINDOWS_FLOAT\n#define DOUBLE WINDOWS_DOUBLE\n#endif\n\n#include \"IniParser.h\"\n\n#if defined(_WIN32) || defined(_WIN64)\n#undef UNKNOWN\n#undef CHAR\n#undef SHORT\n#undef INT\n#undef LONG\n#undef FLOAT\n#undef DOUBLE\n#endif\n\n// These Are All The Types That Can Be Parsed\nenum PTYPE {\n    UNKNOWN,\n    CHAR,\n    SHORT,\n    INT,\n    LONG,\n    FLOAT,\n    DOUBLE,\n    STRING\n};\n\n// These Are Used In The File To Denote Type\n#define CHAR_BYTE 'b'\n#define CHAR_SHORT 'h'\n#define CHAR_INT 'i'\n#define CHAR_LONG 'l'\n#define CHAR_FLOAT 'f'\n#define CHAR_DOUBLE 'd'\n#define CHAR_STRING 's'\n\nlong GetFileSize(const char* filename) {\n    // Check The File Path\n    if(!filename) return -1;\n\n    // Use File Information For The Size\n    struct stat stat_buf;\n    int rc = stat(filename, &stat_buf);\n    return rc == 0 ? stat_buf.st_size : -1;\n}\n\n// Helpers For Navigating Within The String\ninline char* GoToNonWhitespaceML(char* s) {\n    // Ensure Argument\n    if(!s) return 0;\n\n    while(true) {\n        switch(*s) {\n            // All Whitespace Is Skipped\n            case ' ':\n            case '\\t':\n            case '\\r':\n            case '\\n':\n                s++;\n                break;\n            default:\n                return s;\n        }\n    }\n}\ninline char* GoToNonWhitespace(char* s) {\n    // Ensure Argument\n    if(!s) return 0;\n\n    while(true) {\n        switch(*s) {\n            // Only Spaces And Tabs Count As Whitespace\n            case ' ':\n            case '\\t':\n                s++;\n                break;\n            default:\n                return s;\n        }\n    }\n}\n\n// Custom Numerical Converters For Integers\nunsigned long int ExtractHex(char* s) {\n    // Ensure Argument\n    if(!s) return 0;\n\n    // Get Rid Of Beginning Whitespace\n    s = GoToNonWhitespace(s);\n\n    // Check For Inverting Values\n    bool flip = false;\n    if(*s == '~') {\n        flip = true;\n        s++;\n    }\n\n    // Parse The Value\n    int i = 0;\n    unsigned long int num = 0;\n    while(true) {\n        switch(s[i]) {\n            case 0:\n            case ' ':\n            case '\\t':\n            case '\\r':\n            case '\\n':\n                // The End Of The String Has Been Reached\n                return flip ? ~num : num;\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                // Append Values In Hex Form\n                num <<= 4;\n                num |= s[i] - '0';\n                break;\n            case 'a':\n            case 'b':\n            case 'c':\n            case 'd':\n            case 'e':\n            case 'f':\n                // Append Values In Hex Form\n                num <<= 4;\n                num |= s[i] - 'a' + 10;\n                break;\n            case 'A':\n            case 'B':\n            case 'C':\n            case 'D':\n            case 'E':\n            case 'F':\n                // Append Values In Hex Form\n                num <<= 4;\n                num |= s[i] - 'A' + 10;\n                break;\n            default:\n                // Other Characters Are Unsupported\n#ifdef DEBUG\n                printf(\"Found Unsupported Character While Parsing Hex Value\\n\");\n#endif // DEBUG\n                return flip ? ~num : num;\n        }\n\n        // Move To The Next Character\n        i++;\n    }\n}\nunsigned long int ExtractOctal(char* s) {\n    // Ensure Argument\n    if(!s) return 0;\n\n    // Get Rid Of Beginning Whitespace\n    s = GoToNonWhitespace(s);\n\n    // Check For Hex Value\n    if(s[0] == 'x') return ExtractHex(s + 1);\n\n    // Check For Inverting Values\n    bool flip = false;\n    if(*s == '~') {\n        flip = true;\n        s++;\n    }\n\n    // Parse The Value\n    int i = 0;\n    unsigned long int num = 0;\n    while(true) {\n        switch(s[i]) {\n            case 0:\n            case ' ':\n            case '\\t':\n            case '\\r':\n            case '\\n':\n                // The End Of The String Has Been Reached\n                return flip ? ~num : num;\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                // Append Values In Octal Form\n                num <<= 3;\n                num |= s[i] - '0';\n                break;\n            default:\n                // Other Characters Are Unsupported\n#ifdef DEBUG\n                printf(\"Found Unsupported Character While Parsing Hex Value\\n\");\n#endif // DEBUG\n                return flip ? ~num : num;\n        }\n\n        // Move To The Next Character\n        i++;\n    }\n}\nunsigned long int ExtractNumber(char* s) {\n    // Ensure Argument\n    if(!s) return 0;\n\n    // Get Rid Of Beginning Whitespace\n    s = GoToNonWhitespace(s);\n\n    // Check For Octal Value\n    if(s[0] == '0') return ExtractOctal(s + 1);\n\n    // Check For Inverting Values\n    bool flip = false;\n    if(*s == '-') {\n        flip = true;\n        s++;\n    }\n\n    // Parse The Value\n    int i = 0;\n    unsigned long int num = 0;\n    while(true) {\n        switch(s[i]) {\n            case 0:\n            case ' ':\n            case '\\t':\n            case '\\r':\n            case '\\n':\n                // The End Of The String Has Been Reached\n                return flip ? -num : num;\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                // Append Values In Octal Form\n                num *= 10;\n                num += s[i] - '0';\n                break;\n            default:\n                // Other Characters Are Unsupported\n#ifdef DEBUG\n                printf(\"Found Unsupported Character While Parsing Hex Value\\n\");\n#endif // DEBUG\n                return flip ? ~num : num;\n        }\n\n        // Move To The Next Character\n        i++;\n    }\n}\n\n// Helpers To Extract Information From An INI Value\nPTYPE ExtractType(char*& s) {\n    // Ensure Argument\n    if(!s) return UNKNOWN;\n\n    // Go To The First Character In The Type\n    s = GoToNonWhitespaceML(s);\n    if(*s == 0) return UNKNOWN;\n\n    // Transfer Chars To An Enum\n    switch(*s) {\n        case CHAR_BYTE: return CHAR;\n        case CHAR_SHORT: return SHORT;\n        case CHAR_INT: return INT;\n        case CHAR_LONG: return LONG;\n        case CHAR_FLOAT: return FLOAT;\n        case CHAR_DOUBLE: return DOUBLE;\n        case CHAR_STRING: return STRING;\n        default: return UNKNOWN;\n    }\n}\nchar* ExtractValue(char*& s) {\n    int cap = 10, count = 0;\n    char* v = (char*)malloc(cap);\n    while(*s != '}' && *s != 0) {\n        // Check For Escape\n        if(*s == '\\\\') {\n            s++;\n            if(*s == 0) break;\n        }\n\n        // Append The Character\n        v[count++] = *s;\n        s++;\n\n        // Check For String Capacity\n        if(count == cap) {\n            cap <<= 1;\n            v = (char*)realloc(v, cap);\n        }\n    }\n\n    // Check For A Bad Value\n    if(*s == 0) {\n        free(v);\n        return 0;\n    }\n    else s++;\n\n    // Null-terminated\n    v[count] = 0;\n    return v;\n}\n\n// This Actually Parses The File\nint ByteBlit(const char* file, void* dst, int maxSize) {\n    // Keep Track Of The Current Number Of Bytes Read\n    int curSize = 0;\n    char* bytes = (char*)dst;\n\n    // Attempt To Open The File\n    FILE* f;\n    f = fopen(file, \"r\");\n    if(!f) {\n#ifdef DEBUG\n        printf(\"Could Not Open INI File\\nError: %d\", ferror(f));\n#endif // DEBUG\n        throw;\n    }\n\n    long fs = GetFileSize(file);\n    char* data = (char*)malloc(fs);\n    fread(data, fs, 1, f);\n\n    while(curSize < maxSize) {\n        // Extract The Type Of The Data\n        PTYPE pt = ExtractType(data);\n        if(pt == PTYPE::UNKNOWN) break;\n\n        // Move To The First Bracket\n        while(*data != '{' && *data != 0) data++;\n        if(*data == 0) break;\n        data++;\n\n        // Extract The Value Into A New String\n        char* value = ExtractValue(data);\n        if(!value) break;\n\n#define APPENDER(TYPE, SIZE, FUNC) \\\n        if(curSize + 1 <= maxSize) { \\\n            TYPE val = (TYPE)FUNC(value); \\\n            memcpy(bytes + curSize, &val, SIZE); \\\n            curSize += SIZE; \\\n        } \\\n        else maxSize = -1; \\\n        break\n\n        // Copy Value Data Into The Destination Making Sure To Not Go Over Alotted Size\n        switch(pt) {\n            case PTYPE::CHAR: APPENDER(unsigned char, 1, ExtractNumber);\n            case PTYPE::SHORT: APPENDER(unsigned short, 2, ExtractNumber);\n            case PTYPE::INT: APPENDER(unsigned int, 4, ExtractNumber);\n            case PTYPE::LONG: APPENDER(unsigned long int, 8, ExtractNumber);\n            case PTYPE::FLOAT: APPENDER(float, 4, atof);\n            case PTYPE::DOUBLE: APPENDER(double, 8, atof);\n            case PTYPE::STRING: APPENDER(char*, sizeof(char*), );\n            default: break;\n        }\n    }\n\n    // Return Amount Of Data That Was Read\n    return curSize;\n}\n\n// A Test Case\n#ifdef TEST_INIPARSER\nstruct MYSTR {\npublic:\n    int V1;\n    int V2;\n    int V3;\n    int V4;\n    char* VStr;\n};\nint test_main(int argc, char** argv) {\n    MYSTR v;\n    int bytes = ByteBlit(\"src/test/data.ini\", &v, sizeof(MYSTR));\n    printf(v.VStr);\n    return 0;\n}\n#endif // TEST_INIPARSER\n"
  },
  {
    "path": "SoA/IniParser.h",
    "content": "#pragma once\n#include \"Vorb/types.h\"\n\n// Parses A File Into A Block Of Data\n/*\n * Format:\n * type MiscCharacters{data}\n * Example:\n * c - The ASCII A - {0x41}\n */\ni32 ByteBlit(const cString file, void* dst, i32 maxSize);"
  },
  {
    "path": "SoA/InitScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"InitScreen.h\"\n\n#include <Vorb/colors.h>\n#include <Vorb/graphics/GraphicsDevice.h>\n#include <Vorb/graphics/GLStates.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n\n#include \"App.h\"\n#include \"MainMenuLoadScreen.h\"\n#include \"GameManager.h\"\n\n#define INIT_SCREEN_FONT \"Fonts/orbitron_bold-webfont.ttf\"\n#define INIT_SCREEN_FONT_SIZE 32\n#define COLOR_FAILURE Red\n#define COLOR_SUCCESS LimeGreen\n\ni32 InitScreen::getNextScreen() const {\n    return m_app->scrLoad->getIndex();\n}\ni32 InitScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid InitScreen::build() {\n    // Empty\n}\nvoid InitScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid InitScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    buildSpriteResources();\n\n    checkRequirements();\n\n    // Background\n    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);\n    glClearDepth(1.0);\n}\nvoid InitScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    destroySpriteResources();\n}\n\nvoid InitScreen::update(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    // Immediately move to next state\n    m_state = vui::ScreenState::CHANGE_NEXT;\n}\nvoid InitScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    const vui::GameWindow* w = &m_game->getWindow();\n\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    m_sb->render(f32v2(w->getWidth(), w->getHeight()), &vg::SamplerState::LINEAR_WRAP, &vg::DepthState::FULL, &vg::RasterizerState::CULL_NONE);\n}\n\nvoid InitScreen::buildSpriteResources() {\n    m_sb = new vg::SpriteBatch(true, true);\n    m_font = new vg::SpriteFont();\n    m_font->init(INIT_SCREEN_FONT, INIT_SCREEN_FONT_SIZE);\n}\nvoid InitScreen::destroySpriteResources() {\n    m_sb->dispose();\n    delete m_sb;\n    m_sb = nullptr;\n\n    m_font->dispose();\n    delete m_font;\n    m_font = nullptr;\n}\n\nvoid InitScreen::checkRequirements() {\n    static const f32 textSize = 30.0f;\n    static const f32 textOffset = 5.0f;\n\n    m_canContinue = true;\n\n    const vui::GameWindow* w = &m_game->getWindow();\n\n    f32v2 pos(0, 0);\n    f32v2 rectSize(w->getWidth(), textSize + textOffset * 2.0f);\n    f32v2 textOff(textOffset, textOffset);\n\n    // Check If Application Can Proceed\n#define INIT_BRANCH(MESSAGE) { \\\n    m_sb->draw(0, pos, rectSize, color::COLOR_FAILURE, 0.5f); \\\n    m_sb->drawString(m_font, MESSAGE, pos + textOff, textSize, 1.0f, color::White); \\\n    m_canContinue = false; \\\n    } else { \\\n        m_sb->draw(0, pos, rectSize, color::COLOR_SUCCESS, 0.5f); \\\n        m_sb->drawString(m_font, MESSAGE, pos + textOff, textSize, 1.0f, color::White); \\\n    } \\\n    pos.y += rectSize.y;\n\n    const vg::GraphicsDeviceProperties& gdProps = vg::GraphicsDevice::getCurrent()->getProperties();\n    m_sb->begin();\n    if (gdProps.glVersionMajor < 3) INIT_BRANCH(\"OpenGL Version\");\n    if (!GLEW_VERSION_2_1) INIT_BRANCH(\"GLEW 2.1\");\n    if (gdProps.maxTextureUnits < 8) INIT_BRANCH(\"Texture Units\");\n\n    // Inform User What Will Happen\n    pos.y += textSize * 0.5f;\n    if (m_canContinue) {\n        m_sb->draw(0, pos, rectSize, color::COLOR_SUCCESS, 0.5f);\n        m_sb->drawString(m_font, \"Application Will Proceed\", pos + textOff, textSize, 1.0f, color::White);\n    } else {\n        m_sb->draw(0, pos, rectSize, color::COLOR_FAILURE, 0.5f);\n        m_sb->drawString(m_font, \"Application Will Now Exit\", pos + textOff, textSize, 1.0f, color::White);\n    }\n    m_sb->drawString(m_font, \"Press Any Key To Continue\", f32v2(10.0f, w->getHeight() - 30.0f), 24.0f, 1.0f, color::LightGray);\n    m_sb->end(vg::SpriteSortMode::TEXTURE);\n\n#ifdef DEBUG\n    printf(\"System Met Minimum Requirements\\n\");\n#endif // DEBUG\n}\n"
  },
  {
    "path": "SoA/InitScreen.h",
    "content": "#pragma once\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/VorbPreDecl.inl>\n\nclass App;\nDECL_VG(class SpriteBatch;  class SpriteFont);\n\nclass InitScreen : public vui::IAppScreen<App> {\npublic:\n    CTOR_APP_SCREEN_INL(InitScreen, App) {\n    }\n\n    virtual i32 getNextScreen() const;\n    virtual i32 getPreviousScreen() const;\n\n    virtual void build();\n    virtual void destroy(const vui::GameTime& gameTime);\n\n    virtual void onEntry(const vui::GameTime& gameTime);\n    virtual void onExit(const vui::GameTime& gameTime);\n\n    virtual void update(const vui::GameTime& gameTime);\n    virtual void draw(const vui::GameTime& gameTime);\n\nprivate:\n    void buildSpriteResources();\n    void destroySpriteResources();\n\n    // Check Requirements And Draws Results\n    void checkRequirements();\n\n    vg::SpriteBatch* m_sb;\n    vg::SpriteFont* m_font;\n    bool m_canContinue;\n};\n"
  },
  {
    "path": "SoA/InputMapper.cpp",
    "content": "#include \"stdafx.h\"\n#include \"InputMapper.h\"\n\n#include <Vorb/io/Keg.h>\n#include <Vorb/io/IOManager.h>\n\n#include \"GameManager.h\"\n#include \"Inputs.h\"\n\n#include \"VirtualKeyKegDef.inl\"\n\nstruct InputKegArray {\n    Array<VirtualKey> defaultKey;\n    Array<VirtualKey> key;\n};\nKEG_TYPE_DECL(InputKegArray);\nKEG_TYPE_DEF(InputKegArray, InputKegArray, kt) {\n    using namespace keg;\n    kt.addValue(\"defaultKey\", Value::array(offsetof(InputKegArray, defaultKey), Value::custom(0, \"VirtualKey\", true)));\n    kt.addValue(\"key\", Value::array(offsetof(InputKegArray, key), Value::custom(0, \"VirtualKey\", true)));\n}\nInputMapper::InputMapper() {\n    memset(m_keyStates, 0, sizeof(m_keyStates));\n}\n\nInputMapper::~InputMapper() {\n    stopInput();\n}\n\nbool InputMapper::getInputState(const InputID id) {\n    // Check Input\n    if (id < 0 || id >= (int)m_inputs.size()) return false;\n    return m_keyStates[m_inputs.at(id).key];\n}\n\nInputMapper::InputID InputMapper::createInput(const nString& inputName, VirtualKey defaultKey) {\n    InputID id = getInputID(inputName);\n    if (id >= 0) return id;\n    id = m_inputs.size();\n    m_inputLookup[inputName] = id;\n    m_inputs.emplace_back(id, inputName, defaultKey, this);\n    m_keyCodeMap[m_inputs.back().key].push_back(id);\n    return id;\n}\n\nInputMapper::InputID InputMapper::getInputID(const nString& inputName) const {\n    auto iter = m_inputLookup.find(inputName);\n\n    if (iter != m_inputLookup.end()) {\n        return iter->second;\n    } else {\n        return -1;\n    }\n}\n\nvoid InputMapper::loadInputs(const nString &location /* = INPUTMAPPER_DEFAULT_CONFIG_LOCATION */) {\n    vio::IOManager iom; //TODO PASS IN\n    nString data;\n\n    // If the file doesn't exist, just make it with defaults\n    if (!iom.fileExists(location)) {\n        saveInputs(location);\n        return;\n    }\n\n    iom.readFileToString(location.c_str(), data);\n   \n    if (data.length() == 0) {\n        fprintf(stderr, \"Failed to load %s\", location.c_str());\n        throw 33;\n    }\n\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        perror(location.c_str());\n        context.reader.dispose();\n        throw 34;\n    }\n\n    // Manually parse yml file\n    auto f = makeFunctor([&] (Sender, const nString& name, keg::Node value) {\n        InputKegArray kegArray;\n        \n        keg::parse((ui8*)&kegArray, value, context, &KEG_GET_TYPE(InputKegArray));\n        \n        // TODO(Ben): Somehow do multikey support\n        // Right now its only using the first key\n        InputID id = m_inputs.size();\n        m_inputs.emplace_back(id, name, kegArray.defaultKey[0], this);\n        m_keyCodeMap[m_inputs.back().key].push_back(id);\n\n        if (kegArray.key.size()) {\n            m_inputs.back().key = kegArray.key[0];\n        } else {\n            m_inputs.back().key = kegArray.defaultKey[0];\n        }\n\n        m_inputLookup[name] = id;\n\n    });\n    context.reader.forAllInMap(node, &f);\n    context.reader.dispose();\n}\n\nvoid InputMapper::startInput() {\n    if (!m_receivingInput) {\n        vui::InputDispatcher::mouse.onButtonDown += makeDelegate(this, &InputMapper::onMouseButtonDown);\n        vui::InputDispatcher::mouse.onButtonUp += makeDelegate(this, &InputMapper::onMouseButtonDown);\n        vui::InputDispatcher::key.onKeyDown += makeDelegate(this, &InputMapper::onKeyDown);\n        vui::InputDispatcher::key.onKeyUp += makeDelegate(this, &InputMapper::onKeyUp);\n        m_receivingInput = true;\n    }\n}\nvoid InputMapper::stopInput() {\n    if (m_receivingInput) {\n        vui::InputDispatcher::mouse.onButtonDown -= makeDelegate(this, &InputMapper::onMouseButtonDown);\n        vui::InputDispatcher::mouse.onButtonUp -= makeDelegate(this, &InputMapper::onMouseButtonDown);\n        vui::InputDispatcher::key.onKeyDown -= makeDelegate(this, &InputMapper::onKeyDown);\n        vui::InputDispatcher::key.onKeyUp -= makeDelegate(this, &InputMapper::onKeyUp);\n        m_receivingInput = false;\n    }\n}\n\nvoid InputMapper::saveInputs(const nString &filePath VORB_UNUSED /* = INPUTMAPPER_DEFAULT_CONFIG_LOCATION */) {\n    //TODO(Ben): Implement and remove VORB_UNUSED tag.\n   // vio::IOManager iom;\n    // Just build the data string manually then write it\n   \n   /* bool tmp;\n    keg::Enum enm;\n    nString data = \"\";\n    for (auto& input : m_inputs) {\n        data += input->name + \":\\n\";\n        data += \"  defaultKey:\\n\";\n        data += \"    - \" + keg::getEnum(tmp, .getValue()\n    }*/\n}\n\nVirtualKey InputMapper::getKey(const InputID id) {\n    if (id < 0 || id >= (int)m_inputs.size()) return VKEY_HIGHEST_VALUE;\n    return m_inputs.at(id).key;\n}\n\nvoid InputMapper::setKey(const InputID id, VirtualKey key) {\n    // Need to remove old key state\n    VirtualKey oldKey = m_inputs.at(id).key;\n    auto it = m_keyCodeMap.find(oldKey);\n    auto& vec = it->second;\n    for (size_t i = 0; i < vec.size(); i++) {\n        // Remove the input from the vector keyed on VirtualKey\n        if (vec[i] == id) {\n            vec[i] = vec.back();\n            vec.pop_back();\n            break;\n        }\n    }\n    // Set new key\n    m_keyCodeMap[key].push_back(id);\n    m_inputs[id].key = key;\n}\n\nvoid InputMapper::setKeyToDefault(const InputID id) {\n    if (id < 0 || id >= (int)m_inputs.size()) return;\n    setKey(id, m_inputs.at(id).defaultKey);\n}\n\nvoid InputMapper::onMouseButtonDown(Sender, const vui::MouseButtonEvent& e) {\n    ui32 code = VKEY_HIGHEST_VALUE + (ui32)e.button;\n    if (!m_keyStates[code]) {\n        m_keyStates[code] = true;\n        // TODO(Ben): input mapping for mouse\n        //auto& it = m_keyCodeMap.find((VirtualKey)e.keyCode);\n        //if (it != m_keyCodeMap.end()) {\n        //    // Call all events mapped to that virtual key\n        //    for (auto& id : it->second) {\n        //        m_inputs[id].downEvent(e.keyCode);\n        //    }\n        //}\n    }\n}\n\nvoid InputMapper::onMouseButtonUp(Sender, const vui::MouseButtonEvent& e) {\n    ui32 code = VKEY_HIGHEST_VALUE + (ui32)e.button;\n    m_keyStates[code] = false;\n    // TODO(Ben): input mapping for mouse\n    //auto& it = m_keyCodeMap.find((VirtualKey)e.keyCode);\n    //if (it != m_keyCodeMap.end()) {\n    //    // Call all events mapped to that virtual key\n    //    for (auto& id : it->second) {\n    //        m_inputs[id].upEvent(e.keyCode);\n    //    }\n    //} \n}\n\nvoid InputMapper::onKeyDown(Sender, const vui::KeyEvent& e) {\n    if (!m_keyStates[e.keyCode]) {\n        m_keyStates[e.keyCode] = true;\n        auto it = m_keyCodeMap.find((VirtualKey)e.keyCode);\n        if (it != m_keyCodeMap.end()) {\n            // Call all events mapped to that virtual key\n            for (auto& id : it->second) {\n                m_inputs[id].downEvent(e.keyCode);\n            }\n        }\n    }\n}\n\nvoid InputMapper::onKeyUp(Sender, const vui::KeyEvent& e) {\n    m_keyStates[e.keyCode] = false;\n    auto it = m_keyCodeMap.find((VirtualKey)e.keyCode);\n    if (it != m_keyCodeMap.end()) {\n        // Call all events mapped to that virtual key\n        for (auto& id : it->second) {\n            m_inputs[id].upEvent(e.keyCode);\n        }\n    } \n}\n"
  },
  {
    "path": "SoA/InputMapper.h",
    "content": "/// \n///  InputMapper.h\n///  Seed of Andromeda\n///\n///  Created by Frank McCoy\n///  Refactored by Ben Arnold on Mar 25 2015\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  Summary:\n///  Handles mapping of input for keys and buttons.\n///\n\n#pragma once\n\n#ifndef Input_Manager_h\n#define Input_Manager_h\n\n#include <Vorb/Event.hpp>\n#include <Vorb/ui/InputDispatcher.h>\n\n#define INPUTMAPPER_DEFAULT_CONFIG_LOCATION \"Data/KeyConfig.yml\"\n\n/// Handles all the user input through the mouse, keyboard and gamepad.\n/// @author Frank McCoy and Ben Arnold\nclass InputMapper {\npublic:\n    typedef Event<ui32>::Subscriber Listener;\n    typedef i32 InputID;\n\n    /// Constructor.\n    InputMapper();\n    /// Destructor.\n    ~InputMapper();\n\n    /// The data for a single Input.\n    class Input {\n    public:\n        Input(InputID ID, const nString& nm, VirtualKey defKey, InputMapper* parent) :\n        id(ID),\n        name(nm),\n        defaultKey(defKey),\n        key(defKey),\n        upEvent(parent),\n        downEvent(parent){\n            // Empty\n        }\n        InputID id;\n        nString name; ///< The name of the input.\n        VirtualKey defaultKey; ///< The default key.\n        VirtualKey key; ///< The actual key.\n        Event<ui32> upEvent; ///< The event for when the key is released\n        Event<ui32> downEvent; ///< The event for when the key is pressed\n    };\n    typedef std::vector<Input> InputList;\n    typedef std::unordered_map<nString, InputID> InputMap;\n\n    /// Returns the state of an input\n    /// @param id: The id of the input which is being looked up.\n    /// @return The state of the positive key in the input.\n    bool getInputState(const InputID id);\n\n    /// Creates a single key input.\n    /// If the input already exists the old ID is returned and no data is modified.\n    /// @param inputName: The name of the input to create.\n    /// @param defaultKey: The default key(positive) for the new input.\n    /// @return The id of the new input.\n    InputID createInput(const nString& inputName, VirtualKey defaultKey); // Single key\n  \n\n    /// Get the positive key of the supplied input.\n    /// If the input does not exist return UINT32_MAX.\n    /// @param id: The id of the input to look up.\n    /// @return The id of the positive key of the input.\n    VirtualKey getKey(const InputID id);\n\n    /// Set the positive key of the supplied input.\n    /// @param id: The id of the input to look up.\n    /// @param key: The key to set the keys' positive key to.\n    void setKey(const InputID id, VirtualKey key);\n\n    /// Resets the axes' positive key to the default.\n    /// @param id: The input to reset to default.\n    void setKeyToDefault(const InputID id);\n\n    /// Gets the input ID for the supplied input.\n    /// If supplied an invalid inputName the function returns -1.\n    /// @param inputName: The name of the input to look up.\n    /// @return The id of the supplied input.\n    InputID getInputID(const nString& inputName) const;\n\n    /// Reads all the axes stored in a given ini file.\n    /// @param filePath: The local path to the file to load axes from.\n    void loadInputs(const nString& filePath = INPUTMAPPER_DEFAULT_CONFIG_LOCATION);\n\n    /// Saves currently stored axes to the given file path.\n    /// @param filePath: The local filePath to the file to save the loaded axes into.\n    void saveInputs(const nString& filePath = INPUTMAPPER_DEFAULT_CONFIG_LOCATION);\n\n    /// Begins receiving input events from dispatcher\n    void startInput();\n    /// Stops receiving input events from dispatcher\n    void stopInput();\n\n    const bool& isRecievingInput() const { return m_receivingInput; }\n\n    /// Gets the input associated with the InputID\n    Input& get(InputID i) {\n        return m_inputs[i];\n    }\n    Input& operator[](InputID i) {\n        return m_inputs[i];\n    }\n\n    const InputMap& getInputLookup() const { return m_inputLookup; }\n\nprivate:\n    void onMouseButtonDown(Sender, const vui::MouseButtonEvent& e);\n    void onMouseButtonUp(Sender, const vui::MouseButtonEvent& e);\n    void onKeyDown(Sender, const vui::KeyEvent& e);\n    void onKeyUp(Sender, const vui::KeyEvent& e);\n   \n    InputList m_inputs; ///< All the stored axes.\n    InputMap m_inputLookup; ///< A map of input names to input IDs for quick look up.\n    std::unordered_map<VirtualKey, std::vector<InputID> > m_keyCodeMap; ///< Map of keycodes to active input\n    \n    /// Assuming vui::MouseButton wont change...\n    bool m_keyStates[VKEY_HIGHEST_VALUE + (ui32)vui::MouseButton::X2]; ///< The state of the keys and mouse buttons this frame.\n  \n    bool m_receivingInput = false; ///< Tracks input reception state\n    AutoDelegatePool m_inputHooks; ///< Stores input reception function hooks for deallocation\n};\n\n#endif //Input_Manager_h\n"
  },
  {
    "path": "SoA/Inputs.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Inputs.h\"\n\n#include <SDL2/SDL_mouse.h>\n\n#include \"GameManager.h\"\n\n// Input Commands Sorted Alphabetically\nInputMapper::InputID INPUT_BACKWARD = -1;\nInputMapper::InputID INPUT_BLOCK_DRAG = -1;\nInputMapper::InputID INPUT_BLOCK_SCANNER = -1;\nInputMapper::InputID INPUT_CROUCH = -1;\nInputMapper::InputID INPUT_CYCLE_COLOR_FILTER = -1;\nInputMapper::InputID INPUT_DEBUG = -1;\nInputMapper::InputID INPUT_DEV_CONSOLE = -1;\nInputMapper::InputID INPUT_DRAW_MODE = -1;\nInputMapper::InputID INPUT_EXIT = -1;\nInputMapper::InputID INPUT_FLASH_LIGHT = -1;\nInputMapper::InputID INPUT_FLY = -1;\nInputMapper::InputID INPUT_FORWARD = -1;\nInputMapper::InputID INPUT_GRID = -1;\nInputMapper::InputID INPUT_HUD = -1;\nInputMapper::InputID INPUT_INVENTORY = -1;\nInputMapper::InputID INPUT_JUMP = -1;\nInputMapper::InputID INPUT_LEFT = -1;\nInputMapper::InputID INPUT_LEFT_ROLL = -1;\nInputMapper::InputID INPUT_MARKER = -1;\nInputMapper::InputID INPUT_MEGA_SPEED = -1;\nInputMapper::InputID INPUT_MOUSE_LEFT = -1;\nInputMapper::InputID INPUT_MOUSE_RIGHT = -1;\nInputMapper::InputID INPUT_NIGHT_VISION = -1;\nInputMapper::InputID INPUT_NIGHT_VISION_RELOAD = -1;\nInputMapper::InputID INPUT_PAUSE = -1;\nInputMapper::InputID INPUT_PHYSICS_BLOCK_UPDATES = -1;\nInputMapper::InputID INPUT_PLANET_DRAW_MODE = -1;\nInputMapper::InputID INPUT_PLANET_ROTATION = -1;\nInputMapper::InputID INPUT_RANDOM_DEBUG = -1;\nInputMapper::InputID INPUT_RELOAD_BLOCKS = -1;\nInputMapper::InputID INPUT_RELOAD_SHADERS = -1;\nInputMapper::InputID INPUT_RELOAD_SYSTEM = -1;\nInputMapper::InputID INPUT_RELOAD_TARGET = -1;\nInputMapper::InputID INPUT_RELOAD_TEXTURES = -1;\nInputMapper::InputID INPUT_RELOAD_UI = -1;\nInputMapper::InputID INPUT_RIGHT = -1;\nInputMapper::InputID INPUT_RIGHT_ROLL = -1;\nInputMapper::InputID INPUT_SCAN_WSO = -1;\nInputMapper::InputID INPUT_SCREENSHOT = -1;\nInputMapper::InputID INPUT_SONAR = -1;\nInputMapper::InputID INPUT_SPEED_TIME = -1;\nInputMapper::InputID INPUT_SPRINT = -1;\nInputMapper::InputID INPUT_TIME_BACK = -1;\nInputMapper::InputID INPUT_TIME_FORWARD = -1;\nInputMapper::InputID INPUT_TOGGLE_AR = -1;\nInputMapper::InputID INPUT_TOGGLE_UI = -1;\nInputMapper::InputID INPUT_UPDATE_FRUSTUM = -1;\nInputMapper::InputID INPUT_WATER_UPDATE = -1;\nInputMapper::InputID INPUT_ZOOM = -1;\n\n\n// Reduce Some Code\n#define CREATE_INPUT(ID,KEY,VAR) \\\n    VAR = inputManager->createInput(#ID, KEY);\n\n// Generate Input Handles\nvoid initInputs(InputMapper* inputManager) {\n //   CREATE_INPUT(Random Debug, VKEY_6, INPUT_RANDOM_DEBUG);\n\n    // The Greatest Input In The Cosmos\n    CREATE_INPUT(Pause, VKEY_ESCAPE, INPUT_PAUSE);\n    \n    // Dev Console\n    CREATE_INPUT(Dev Console, VKEY_GRAVE, INPUT_DEV_CONSOLE);\n\n    // Game Information\n    CREATE_INPUT(Debug, VKEY_H, INPUT_DEBUG);\n    CREATE_INPUT(Inventory, VKEY_TAB, INPUT_INVENTORY);\n    CREATE_INPUT(HUD, VKEY_T, INPUT_HUD);\n\n    // Visual Aid\n    CREATE_INPUT(Zoom, VKEY_RCTRL, INPUT_ZOOM);\n    CREATE_INPUT(Sonar, VKEY_R, INPUT_SONAR);\n    CREATE_INPUT(Flash Light, VKEY_L, INPUT_FLASH_LIGHT);\n    CREATE_INPUT(Night Vision, VKEY_N, INPUT_NIGHT_VISION);\n\n    // Refreshing Functions\n    CREATE_INPUT(Reload Textures, VKEY_F4, INPUT_RELOAD_TEXTURES);\n    CREATE_INPUT(Reload Blocks, VKEY_F6, INPUT_RELOAD_BLOCKS);\n    CREATE_INPUT(Reload Shaders, VKEY_F11, INPUT_RELOAD_SHADERS);\n    CREATE_INPUT(Reload System, VKEY_F10, INPUT_RELOAD_SYSTEM);\n    CREATE_INPUT(Reload UI, VKEY_F5, INPUT_RELOAD_UI);\n    CREATE_INPUT(Reload Night Vision, VKEY_F3, INPUT_NIGHT_VISION_RELOAD);\n    CREATE_INPUT(Reload Target, VKEY_F12, INPUT_RELOAD_TARGET);\n\n    // Visual Debugging\n    CREATE_INPUT(Grid Toggle, VKEY_G, INPUT_GRID);\n    CREATE_INPUT(Cycle Draw Mode, VKEY_M, INPUT_DRAW_MODE);\n    CREATE_INPUT(Planet Draw Mode, VKEY_J, INPUT_PLANET_DRAW_MODE);\n    CREATE_INPUT(Update Frustum, VKEY_U, INPUT_UPDATE_FRUSTUM);\n    CREATE_INPUT(Cycle Color Filter, VKEY_C, INPUT_CYCLE_COLOR_FILTER);\n\n    // Movement\n    CREATE_INPUT(Fly, VKEY_F, INPUT_FLY);\n    CREATE_INPUT(Sprint, VKEY_LSHIFT, INPUT_SPRINT);\n    CREATE_INPUT(Crouch, VKEY_LCTRL, INPUT_CROUCH);\n    CREATE_INPUT(Mega Speed, VKEY_LSHIFT, INPUT_MEGA_SPEED);\n    CREATE_INPUT(Jump, VKEY_SPACE, INPUT_JUMP);\n    CREATE_INPUT(Forward, VKEY_W, INPUT_FORWARD);\n    CREATE_INPUT(Left, VKEY_A, INPUT_LEFT);\n    CREATE_INPUT(Right, VKEY_D, INPUT_RIGHT);\n    CREATE_INPUT(Backward, VKEY_S, INPUT_BACKWARD);\n    CREATE_INPUT(Right Roll, VKEY_E, INPUT_RIGHT_ROLL);\n    CREATE_INPUT(Left Roll, VKEY_Q, INPUT_LEFT_ROLL);\n\n    // Gameplay\n    CREATE_INPUT(Marker, VKEY_C, INPUT_MARKER);\n    CREATE_INPUT(Scan WSO, VKEY_LEFTBRACKET, INPUT_SCAN_WSO);\n\n    // Physics\n    CREATE_INPUT(Water Update, VKEY_N, INPUT_WATER_UPDATE);\n    CREATE_INPUT(Update Physics Blocks, VKEY_P, INPUT_PHYSICS_BLOCK_UPDATES);\n\n    // Mouse Buttons\n    CREATE_INPUT(Mouse Right, (VirtualKey)SDL_BUTTON_RIGHT, INPUT_MOUSE_RIGHT);\n    CREATE_INPUT(Mouse Left, (VirtualKey)SDL_BUTTON_LEFT, INPUT_MOUSE_LEFT);\n    \n    // Block Utilities\n    CREATE_INPUT(Block Scanner, VKEY_Q, INPUT_BLOCK_SCANNER);\n    CREATE_INPUT(Block Select, VKEY_B, INPUT_BLOCK_DRAG);\n\n    // Main Menu\n    CREATE_INPUT(Exit, VKEY_ESCAPE, INPUT_EXIT);\n    CREATE_INPUT(Toggle UI, VKEY_U, INPUT_TOGGLE_UI);\n    CREATE_INPUT(Toggle AR, VKEY_A, INPUT_TOGGLE_AR);\n    CREATE_INPUT(Speed Time, VKEY_LCTRL, INPUT_SPEED_TIME);\n    CREATE_INPUT(Take Screenshot, VKEY_F2, INPUT_SCREENSHOT);\n    CREATE_INPUT(Time Back, VKEY_LEFT, INPUT_TIME_BACK);\n    CREATE_INPUT(Time Forward, VKEY_RIGHT, INPUT_TIME_FORWARD);\n}"
  },
  {
    "path": "SoA/Inputs.h",
    "content": "///\n/// Inputs.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 29 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Hard-coded list of inputs\n/// TODO: Remove\n///\n\n#pragma once\n\n#ifndef Inputs_h__\n#define Inputs_h__\n\n#include \"InputMapper.h\"\n\n// These can not be an enum. They are very likely to change values at runtime!\nextern InputMapper::InputID INPUT_BACKWARD;\nextern InputMapper::InputID INPUT_BLOCK_DRAG;\nextern InputMapper::InputID INPUT_BLOCK_SCANNER;\nextern InputMapper::InputID INPUT_CROUCH;\nextern InputMapper::InputID INPUT_CYCLE_COLOR_FILTER;\nextern InputMapper::InputID INPUT_DEBUG;\nextern InputMapper::InputID INPUT_DEV_CONSOLE;\nextern InputMapper::InputID INPUT_DRAW_MODE;\nextern InputMapper::InputID INPUT_EXIT;\nextern InputMapper::InputID INPUT_FLASH_LIGHT;\nextern InputMapper::InputID INPUT_FLY;\nextern InputMapper::InputID INPUT_FORWARD;\nextern InputMapper::InputID INPUT_GRID;\nextern InputMapper::InputID INPUT_HUD;\nextern InputMapper::InputID INPUT_INVENTORY;\nextern InputMapper::InputID INPUT_JUMP;\nextern InputMapper::InputID INPUT_LEFT;\nextern InputMapper::InputID INPUT_LEFT_ROLL;\nextern InputMapper::InputID INPUT_MARKER;\nextern InputMapper::InputID INPUT_MEGA_SPEED;\nextern InputMapper::InputID INPUT_MOUSE_LEFT;\nextern InputMapper::InputID INPUT_MOUSE_RIGHT;\nextern InputMapper::InputID INPUT_NIGHT_VISION;\nextern InputMapper::InputID INPUT_NIGHT_VISION_RELOAD;\nextern InputMapper::InputID INPUT_PAUSE;\nextern InputMapper::InputID INPUT_PHYSICS_BLOCK_UPDATES;\nextern InputMapper::InputID INPUT_PLANET_DRAW_MODE;\nextern InputMapper::InputID INPUT_PLANET_ROTATION;\nextern InputMapper::InputID INPUT_RANDOM_DEBUG;\nextern InputMapper::InputID INPUT_RELOAD_BLOCKS;\nextern InputMapper::InputID INPUT_RELOAD_SHADERS;\nextern InputMapper::InputID INPUT_RELOAD_SYSTEM;\nextern InputMapper::InputID INPUT_RELOAD_TARGET;\nextern InputMapper::InputID INPUT_RELOAD_TEXTURES;\nextern InputMapper::InputID INPUT_RELOAD_UI;\nextern InputMapper::InputID INPUT_RIGHT;\nextern InputMapper::InputID INPUT_RIGHT_ROLL;\nextern InputMapper::InputID INPUT_SCAN_WSO;\nextern InputMapper::InputID INPUT_SCREENSHOT;\nextern InputMapper::InputID INPUT_SONAR;\nextern InputMapper::InputID INPUT_SPEED_TIME;\nextern InputMapper::InputID INPUT_SPRINT;\nextern InputMapper::InputID INPUT_TIME_BACK;\nextern InputMapper::InputID INPUT_TIME_FORWARD;\nextern InputMapper::InputID INPUT_TOGGLE_AR;\nextern InputMapper::InputID INPUT_TOGGLE_UI;\nextern InputMapper::InputID INPUT_UPDATE_FRUSTUM;\nextern InputMapper::InputID INPUT_WATER_UPDATE;\nextern InputMapper::InputID INPUT_ZOOM;\n\n// Initialize Input IDs At Runtime\nextern void initInputs(InputMapper* inputManager);\n\n#endif // Inputs_h__\n"
  },
  {
    "path": "SoA/Item.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Item.h\"\n\nItemPack::ItemPack() :\n    onItemDataAddition(this) {\n    // Add default item\n    append(ItemData());\n}\n\nItemID ItemPack::append(ItemData item) {\n    const ItemData* curBlock;\n    ItemID rv;\n    if ((curBlock = hasItem(item.id))) {\n        rv = curBlock->id;\n        item.id = rv;\n        // Overwrite block\n        *const_cast<ItemData*>(curBlock) = item;\n    } else {\n        rv = m_itemList.size();\n        item.id = rv;\n        // Add a new block\n        m_itemList.push_back(item);\n        // Set the correct index\n        m_itemMap[item.name] = rv;\n    }\n    onItemDataAddition(item.id);\n    return rv;\n}\n\nvoid ItemPack::reserveID(const ItemIdentifier& sid, ItemID id) {\n    if (id >= m_itemList.size()) m_itemList.resize(id + 1);\n    m_itemMap[sid] = id;\n    m_itemList[id].id = id;\n}\n"
  },
  {
    "path": "SoA/Item.h",
    "content": "#pragma once\n\n#include <Vorb/types.h>\n#include <Vorb/Event.hpp>\n\nenum class ItemType {\n    NONE, BLOCK, WEAPON, ARMOR, CONSUMABLE, MATERIAL, USABLE, MISC\n};\n\ntypedef nString ItemIdentifier;\ntypedef ui32 ItemID;\n\nconst nString ITEM_TYPE_STRINGS[] = { \"None\", \"Block\", \"Weapon\", \"Armor\", \"Consumable\", \"Material\", \"Usable\", \"Misc\" };\n\n// One or more items. All items are ItemStacks.\nstruct ItemData {\n    ItemIdentifier name = \"?\";\n    ItemType type = ItemType::NONE;\n    ItemID id = 0;\n    f32 value = 0.0f;\n    f32 weight = 0.0f;\n    ui32 maxCount = 1; ///< If this is 1, this can only be a single item.\n    // Certain types don't need certain data\n    union {\n        ui32 maxDurability;\n        ui32 blockID;\n    };\n};\n\n// Container for all item types\n// TODO(Ben): Save and load\nclass ItemPack {\npublic:\n    ItemPack();\n\n    ItemID append(ItemData item);\n\n    void reserveID(const ItemIdentifier& sid, ItemID id);\n\n    const ItemData* hasItem(ItemID id) const {\n        if (id >= m_itemList.size()) {\n            return nullptr;\n        } else {\n            return &m_itemList[id];\n        }\n    }\n    const ItemData* hasItem(const ItemIdentifier& sid) const {\n        auto v = m_itemMap.find(sid);\n        if (v == m_itemMap.end()) {\n            return nullptr;\n        } else {\n            return &m_itemList[v->second];\n        }\n    }\n\n    size_t size() const {\n        return m_itemList.size();\n    }\n\n    /************************************************************************/\n    /* ItemData accessors                                                   */\n    /************************************************************************/\n    ItemData& operator[](const size_t& index) {\n        return m_itemList[index];\n    }\n    const ItemData& operator[](const size_t& index) const {\n        return m_itemList[index];\n    }\n    ItemData& operator[](const ItemIdentifier& sid) {\n        return m_itemList[m_itemMap.at(sid)];\n    }\n    const ItemData& operator[](const ItemIdentifier& sid) const {\n        return m_itemList[m_itemMap.at(sid)];\n    }\n    ui16 getItemDataIndex(const ItemIdentifier& sid) const {\n        return m_itemMap.at(sid);\n    }\n\n    const std::unordered_map<ItemIdentifier, ui32>& getItemDataMap() const { return m_itemMap; }\n    const std::vector<ItemData>& getItemDataList() const { return m_itemList; }\n\n    Event<ui16> onItemDataAddition; ///< Signaled when a block is loaded\n\nprivate:\n    // TODO(Ben): worry about runtime resizing\n    std::unordered_map<ItemIdentifier, ui32> m_itemMap; ///< Item indices organized by identifiers\n    std::vector<ItemData> m_itemList; ///< Item data list\n};\n\nstruct ItemStack {\n    ItemID id = 0;\n    ui32 count = 0;\n    ui32 durability = 0;\n    ItemPack* pack = nullptr; ///< Flyweight\n};"
  },
  {
    "path": "SoA/LenseFlareRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"LenseFlareRenderer.h\"\n\n#include \"ModPathResolver.h\"\n#include \"ShaderLoader.h\"\n#include \"Errors.h\"\n\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/graphics/SamplerState.h>\n#include <Vorb/graphics/ShaderManager.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/io/Keg.h>\n\nstruct FlareVertex {\n    f32v2 position;\n    f32v2 uv;\n    f32 offset;\n};\n\nstruct FlareSprite {\n    bool rotate = false;\n    f32 offset;\n    f32 size;\n    ui32 textureIndex;\n};\nKEG_TYPE_DEF_SAME_NAME(FlareSprite, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, FlareSprite, rotate, BOOL);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, FlareSprite, offset, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, FlareSprite, size, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, FlareSprite, textureIndex, UI32);\n}\n\nstruct FlareKegProperties {\n    ui32 spritesPerRow = 1;\n    f32 intensity = 1.0f;\n    Array<FlareSprite> sprites;\n};\nKEG_TYPE_DEF_SAME_NAME(FlareKegProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, FlareKegProperties, spritesPerRow, UI32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, FlareKegProperties, intensity, F32);\n    kt.addValue(\"sprites\", keg::Value::array(offsetof(FlareKegProperties, sprites), keg::Value::custom(0, \"FlareSprite\", false)));\n}\n\nconst int VERTS_PER_QUAD = 4;\nconst int INDICES_PER_QUAD = 6;\n\nLenseFlareRenderer::LenseFlareRenderer() {\n    // Empty\n}\n\nLenseFlareRenderer::~LenseFlareRenderer() {\n    dispose();\n}\n\nvoid LenseFlareRenderer::init(const ModPathResolver* textureResolver) {\n    m_textureResolver = textureResolver;\n}\n\nvoid LenseFlareRenderer::initGL() {\n    { // Load the shader\n        m_program = ShaderLoader::createProgramFromFile(\"Shaders/LensFlare/flare.vert\",\n                                                        \"Shaders/LensFlare/flare.frag\");\n        m_unColor = m_program.getUniform(\"unColor\");\n        // Set constant uniforms\n        m_program.use();\n        glUniform1i(m_program.getUniform(\"unTexture\"), 2);\n        m_program.unuse();\n    }\n\n    { // Load the texture\n        vio::Path path;\n        m_textureResolver->resolvePath(\"Effects/lens_flares.png\", path);\n        vg::ScopedBitmapResource res(vg::ImageIO().load(path));\n        if (!res.data) {\n            fprintf(stderr, \"ERROR: Failed to load Effects/lens_flares.png\\n\");\n        }\n        m_texWidth = res.width;\n        m_texHeight = res.height;\n        m_texture = vg::GpuMemory::uploadTexture(&res, vg::TexturePixelType::UNSIGNED_BYTE,\n                                                 vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_CLAMP_MIPMAP);\n    }\n\n    initMesh();\n}\n\nvoid LenseFlareRenderer::render(const f32m4& VP, const f64v3& relCamPos,\n                                const f32v3& color,\n                                float aspectRatio,\n                                f32 size,\n                                f32 intensity) {\n    if (size <= 0.0f || intensity <= 0.0f) return;\n\n    m_program.use();\n\n    f32v2 dims(size, size * aspectRatio);\n\n    // Bind texture\n    glActiveTexture(GL_TEXTURE2);\n    glBindTexture(GL_TEXTURE_2D, m_texture);\n    // Upload uniforms\n    f32v3 center(-relCamPos);\n    glUniform1f(m_program.getUniform(\"unIntensity\"), intensity * m_intensity);\n    glUniform3fv(m_program.getUniform(\"unCenter\"), 1, &center[0]);\n    glUniform3fv(m_program.getUniform(\"unColor\"), 1, &color[0]);\n    glUniform2fv(m_program.getUniform(\"unDims\"), 1, &dims[0]);\n    glUniformMatrix4fv(m_program.getUniform(\"unVP\"), 1, GL_FALSE, &VP[0][0]);\n\n    glBindVertexArray(m_vao);\n    glDisable(GL_DEPTH_TEST);\n    glDepthMask(GL_FALSE);\n    glDrawElements(GL_TRIANGLES, INDICES_PER_QUAD * m_numSprites, GL_UNSIGNED_SHORT, 0);\n    glEnable(GL_DEPTH_TEST);\n    glDepthMask(GL_TRUE);\n    glBindVertexArray(0);\n\n    m_program.unuse();\n\n}\n\nvoid LenseFlareRenderer::dispose() {\n    if (m_program.isCreated()) m_program.dispose();\n\n    if (m_texture) {\n        vg::GpuMemory::freeTexture(m_texture);\n    }\n    if (m_vbo) {\n        glDeleteBuffers(1, &m_vbo);\n        m_vbo = 0;\n    }\n    if (m_ibo) {\n        glDeleteBuffers(1, &m_ibo);\n        m_ibo = 0;\n    }\n    if (m_vao) {\n        glDeleteVertexArrays(1, &m_vao);\n        m_vao = 0;\n    }\n}\n\nvoid LenseFlareRenderer::loadSprites(FlareKegProperties& kegProps) {\n    nString data;\n    vio::IOManager iom;\n    if (!iom.readFileToString(\"Data/LensFlares/SoA_defaultFlares.yml\", data)) {\n        pError(\"Couldn't find Data/LensFlares/SoA_defaultFlares.yml\");\n    }\n\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n\n    keg::Error err = keg::parse((ui8*)&kegProps, node, context, &KEG_GLOBAL_TYPE(FlareKegProperties));\n    if (err != keg::Error::NONE) {\n        fprintf(stderr, \"Failed to parse Data/LensFlares/SoA_defaultFlares.yml\");\n    }\n}\n\nvoid LenseFlareRenderer::initMesh() {\n\n    FlareKegProperties properties;\n    loadSprites(properties);\n    Array<FlareSprite>& sprites = properties.sprites;\n    m_numSprites = sprites.size();\n    m_intensity = properties.intensity;\n\n    const f32v2 positions[4] = {\n        f32v2(-1.0f, 1.0f),\n        f32v2(-1.0f, -1.0f),\n        f32v2(1.0f, -1.0f),\n        f32v2(1.0f, 1.0f)\n    };\n    const f32v2 uvs[4] = {\n        f32v2(0.0f, 1.0f),\n        f32v2(0.0f, 0.0f),\n        f32v2(1.0f, 0.0f),\n        f32v2(1.0f, 1.0f)\n    };\n    \n    ui32 xSprites = properties.spritesPerRow;\n    ui32 spriteDims = m_texWidth / xSprites;\n    if (spriteDims == 0) pError(\"Lens flare has sprite dims of 0!\");\n    // ui32 ySprites = m_texHeight / spriteDims;\n    f32v2 uvSprite(spriteDims / (f32)m_texWidth,\n                   spriteDims / (f32)m_texHeight);\n\n    const ui16 quadIndices[INDICES_PER_QUAD] = { 0, 1, 2, 2, 3, 0 };\n\n    std::vector<FlareVertex> vertices(m_numSprites * VERTS_PER_QUAD);\n    std::vector<ui16> indices(m_numSprites * INDICES_PER_QUAD);\n    int index = 0;\n\n    for (int i = 0; i < m_numSprites; i++) {\n        FlareSprite& s = sprites[i];\n        f32v2 uvOffset = f32v2(s.textureIndex % xSprites,\n                               s.textureIndex / xSprites) * uvSprite;\n\n        vertices[index].position = positions[0] * s.size;\n        vertices[index + 1].position = positions[1] * s.size;\n        vertices[index + 2].position = positions[2] * s.size;\n        vertices[index + 3].position = positions[3] * s.size;\n        vertices[index].uv = uvs[0] * uvSprite + uvOffset;\n        vertices[index + 1].uv = uvs[1] * uvSprite + uvOffset;\n        vertices[index + 2].uv = uvs[2] * uvSprite + uvOffset;\n        vertices[index + 3].uv = uvs[3] * uvSprite + uvOffset;\n        vertices[index].offset = s.offset;\n        vertices[index + 1].offset = s.offset;\n        vertices[index + 2].offset = s.offset;\n        vertices[index + 3].offset = s.offset;\n        index += 4;\n    }\n    // Set indices\n    for (int i = 0; i < m_numSprites; i++) {\n        for (int j = 0; j < INDICES_PER_QUAD; j++) {\n            indices[i * INDICES_PER_QUAD + j] = quadIndices[j] + i * VERTS_PER_QUAD;\n        }\n    }\n\n    if (m_vbo == 0) glGenBuffers(1, &m_vbo);\n    if (m_ibo == 0) glGenBuffers(1, &m_ibo);\n    if (m_vao == 0) glGenVertexArrays(1, &m_vao);\n\n    // Upload data and make VAO\n    glBindVertexArray(m_vao);\n    vg::GpuMemory::bindBuffer(m_vbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::bindBuffer(m_ibo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n\n    vg::GpuMemory::uploadBufferData(m_vbo, vg::BufferTarget::ARRAY_BUFFER, sizeof(FlareVertex) * vertices.size(), vertices.data());\n    vg::GpuMemory::uploadBufferData(m_ibo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER, sizeof(ui16) * indices.size(), indices.data());\n\n    m_program.enableVertexAttribArrays();\n    glVertexAttribPointer(m_program.getAttribute(\"vPosition\"), 2, GL_FLOAT, GL_FALSE, sizeof(FlareVertex), offsetptr(FlareVertex, position));\n    glVertexAttribPointer(m_program.getAttribute(\"vUV\"), 2, GL_FLOAT, GL_FALSE, sizeof(FlareVertex), offsetptr(FlareVertex, uv));\n    glVertexAttribPointer(m_program.getAttribute(\"vOffset\"), 1, GL_FLOAT, GL_FALSE, sizeof(FlareVertex), offsetptr(FlareVertex, offset));\n\n    glBindVertexArray(0);\n}"
  },
  {
    "path": "SoA/LenseFlareRenderer.h",
    "content": "///\n/// LenseFlareRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 25 Apr 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renders lense flare for stars and other bright objects\n///\n\n#pragma once\n\n#ifndef LenseFlareRenderer_h__\n#define LenseFlareRenderer_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/graphics/GLProgram.h>\n\nclass ModPathResolver;\nstruct FlareKegProperties;\n\nclass LenseFlareRenderer {\npublic:\n    LenseFlareRenderer();\n    ~LenseFlareRenderer();\n\n    void init(const ModPathResolver* textureResolver);\n    void initGL();\n\n    void render(const f32m4& VP, const f64v3& relCamPos,\n                const f32v3& color,\n                float aspectRatio,\n                f32 size,\n                f32 intensity);\n\n    void dispose();\nprivate:\n    void loadSprites(FlareKegProperties& kegProps);\n    void initMesh();\n\n    const ModPathResolver* m_textureResolver = nullptr;\n    vg::GLProgram m_program;\n    VGTexture m_texture = 0;\n    ui32 m_texWidth = 0;\n    ui32 m_texHeight = 0;\n    VGBuffer m_vbo = 0;\n    VGBuffer m_ibo = 0;\n    VGVertexArray m_vao = 0;\n\n    int m_numSprites = 0;\n    f32 m_intensity = 0.0f;\n\n    VGUniform m_unColor = 0; // TODO(Ben): UBO?\n};\n\n#endif // LenseFlareRenderer_h__\n"
  },
  {
    "path": "SoA/LiquidData.h",
    "content": "#pragma once\n\n\nclass LiquidData {\npublic:\n// TODO: Dafuq, this is a lonely world.\n\n    i32 startBlockID;\n    i32 numLevels;\n};"
  },
  {
    "path": "SoA/LiquidVoxelRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"LiquidVoxelRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include \"BlockTexturePack.h\"\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkRenderer.h\"\n#include \"GameRenderParams.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n#include \"SoaOptions.h\"\n\nvoid LiquidVoxelRenderStage::hook(ChunkRenderer* renderer, const GameRenderParams* gameRenderParams) {\n    m_renderer = renderer;\n    m_gameRenderParams = gameRenderParams;\n}\n\nvoid LiquidVoxelRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    ChunkMeshManager* cmm = m_gameRenderParams->chunkMeshmanager;\n    \n    m_renderer->beginLiquid(m_gameRenderParams->blockTexturePack->getAtlasTexture(), m_gameRenderParams->sunlightDirection,\n                            m_gameRenderParams->sunlightColor);\n\n    if (m_gameRenderParams->isUnderwater) glDisable(GL_CULL_FACE);\n    glDepthMask(GL_FALSE);\n\n    const std::vector <ChunkMesh *>& chunkMeshes = cmm->getChunkMeshes();\n    {\n        std::lock_guard<std::mutex> l(cmm->lckActiveChunkMeshes);\n        if (chunkMeshes.empty()) return;\n        for (unsigned int i = 0; i < chunkMeshes.size(); i++) //they are sorted backwards??\n        {\n            m_renderer->drawLiquid(chunkMeshes[i],\n                                   m_gameRenderParams->chunkCamera->getPosition(),\n                                   m_gameRenderParams->chunkCamera->getViewProjectionMatrix());\n        }\n    }\n\n    glDepthMask(GL_TRUE);\n    if (m_gameRenderParams->isUnderwater) glEnable(GL_CULL_FACE);\n\n    m_renderer->end();\n}\n"
  },
  {
    "path": "SoA/LiquidVoxelRenderStage.h",
    "content": "/// \n///  LiquidVoxelRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the render stage for\n///  liquid voxel rendering.\n///\n\n#pragma once\n\n#ifndef LiquidVoxelRenderStage_h__\n#define LiquidVoxelRenderStage_h__\n\n#include \"IRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\nclass MeshManager;\nclass GameRenderParams;\nclass ChunkRenderer;\n\nclass LiquidVoxelRenderStage : public IRenderStage {\npublic:\n    void hook(ChunkRenderer* renderer, const GameRenderParams* gameRenderParams);\n    /// Draws the render stage\n    virtual void render(const Camera* camera) override;\nprivate:\n    ChunkRenderer* m_renderer;\n    const GameRenderParams* m_gameRenderParams = nullptr; ///< Some shared rendering parameters\n};\n\n#endif // LiquidVoxelRenderStage_h__\n"
  },
  {
    "path": "SoA/LoadBar.cpp",
    "content": "#include \"stdafx.h\"\n#include \"LoadBar.h\"\n\n#include <Vorb/graphics/SpriteBatch.h>\n\nLoadBarCommonProperties::LoadBarCommonProperties(const f32v2& offset, const f32v2& size, const f32& moveSpeed, const f32v2& textOffset, const f32& textSize) :\noffsetDirection(offset),\nsize(size),\ntextOffset(textOffset),\ntextSize(textSize),\nmovementSpeed(moveSpeed) {\n    offsetLength = glm::length(offsetDirection);\n    offsetDirection *= (1.0f / offsetLength);\n}\n\nLoadBar::LoadBar(const LoadBarCommonProperties& commonProps) :\n_commonProps(commonProps),\n_startPosition(0),\n_moveDirection(0),\n_lerpAmount(0.0f),\n_colorText(0xff, 0xff, 0xff, 0xff),\n_colorBackground(0x00, 0x00, 0x00, 0xff) {\n}\nLoadBar::~LoadBar() {\n}\n\nvoid LoadBar::expand() {\n    _moveDirection = 1;\n}\nvoid LoadBar::retract() {\n    _moveDirection = -1;\n}\n\nvoid LoadBar::setCommonProperties(const LoadBarCommonProperties& commonProps) {\n    _commonProps = commonProps;\n}\nvoid LoadBar::setStartPosition(const f32v2& position) {\n    _startPosition = position;\n}\nvoid LoadBar::setText(const nString& text) {\n    _text = text;\n}\nvoid LoadBar::setColor(const ColorRGBA8& colorText, const ColorRGBA8& colorBackground) {\n    _colorText = colorText;\n    _colorBackground = colorBackground;\n}\n\nvoid LoadBar::update(f32 dt) {\n    if (_moveDirection == 0) return;\n\n    if (_moveDirection > 0) {\n        // Expand\n        _lerpAmount += _commonProps.movementSpeed * dt;\n        if (_lerpAmount > _commonProps.offsetLength) {\n            _lerpAmount = _commonProps.offsetLength;\n            _moveDirection = 0;\n        }\n    } else {\n        // Retract\n        _lerpAmount -= _commonProps.movementSpeed * dt;\n        if (_lerpAmount < 0.0f) {\n            _lerpAmount = 0.0f;\n            _moveDirection = 0;\n        }\n    }\n}\n\nvoid LoadBar::draw(vg::SpriteBatch* sb, vg::SpriteFont* sf, ui32 backTexture, f32 depth) {\n    f32v2 endPos = _startPosition + (_commonProps.offsetDirection * _lerpAmount);\n    sb->draw(backTexture, endPos, _commonProps.size, _colorBackground, depth);\n    endPos += _commonProps.textOffset;\n    sb->drawString(sf, _text.c_str(), endPos, _commonProps.textSize, 1.0f, _colorText, vg::TextAlign::TOP_LEFT, depth - 0.001f);\n}\n"
  },
  {
    "path": "SoA/LoadBar.h",
    "content": "#pragma once\n\n#include <Vorb/types.h>\n#include <Vorb/VorbPreDecl.inl>\n\nDECL_VG(class SpriteBatch; class SpriteFont);\n\nclass LoadBarCommonProperties {\npublic:\n    LoadBarCommonProperties(const f32v2& offset, const f32v2& size, const f32& moveSpeed, const f32v2& textOffset, const f32& textSize);\n    LoadBarCommonProperties() : LoadBarCommonProperties(f32v2(0), f32v2(0), 0, f32v2(0), 0) {}\n\n    f32v2 offsetDirection;\n    f32 offsetLength;\n    \n    f32v2 size;\n    f32v2 textOffset;\n    f32 textSize;\n\n    f32 movementSpeed;\n};\n\nclass LoadBar {\npublic:\n    LoadBar(const LoadBarCommonProperties& commonProps);\n    LoadBar() : LoadBar(LoadBarCommonProperties()) {}\n    ~LoadBar();\n\n    void expand();\n    void retract();\n\n    bool getIsRetracting() const {\n        return _moveDirection == -1;\n    }\n    bool getIsExpanding() const {\n        return _moveDirection == 1;\n    }\n    bool getIsStationary() const {\n        return _moveDirection == 0;\n    }\n\n    void setCommonProperties(const LoadBarCommonProperties& commonProps);\n    void setStartPosition(const f32v2& position);\n    void setText(const nString& text);\n    void setColor(const ColorRGBA8& colorText, const ColorRGBA8& colorBackground);\n\n    void update(f32 dt);\n\n    void draw(vg::SpriteBatch* sb, vg::SpriteFont* sf, ui32 backTexture, f32 depth);\nprivate:\n    nString _text;\n\n    LoadBarCommonProperties _commonProps;\n\n    f32v2 _startPosition;\n    i32 _moveDirection;\n    f32 _lerpAmount;\n\n    ColorRGBA8 _colorText;\n    ColorRGBA8 _colorBackground;\n};"
  },
  {
    "path": "SoA/LoadContext.h",
    "content": "///\n/// LoadContext.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 4 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// A common context space where assets can\n/// be loaded.\n///\n\n#pragma once\n\n#ifndef LoadContext_h__\n#define LoadContext_h__\n\n#include \"ImageAssetLoader.h\"\n#include \"ShaderAssetLoader.h\"\n\n#include <list>\n\nclass LoadContext {\npublic:\n    void resetWork() {\n        m_totalWork = 0;\n        m_workFinished = 0;\n    }\n    // Call before begin() to indicate how much work is\n    // anticipated.\n    // numTasks is the number of tasks that will be added\n    // via addTask.\n    void addAnticipatedWork(ui32 work) {\n        m_totalWork += work;\n    }\n    void addWorkCompleted(ui32 work) {\n        m_workFinished += work;\n    }\n\n    f32 getPercentComplete() const {\n        return (f32)m_workFinished / (f32)m_totalWork;\n    }\n    bool isWorkComplete() const {\n        return m_workFinished >= m_totalWork;\n    }\n\n    struct {\n        ImageAssetLoader image;\n        ShaderAssetLoader shader;\n    } loaders;\n\n    nString environment;\n    vcore::RPCManager rpcManager;\nprotected:\n    ui32 m_totalWork = 0;\n    volatile ui32 m_workFinished = 0;\n};\n\n// For when the number of tasks is known\nclass StaticLoadContext : public LoadContext {\npublic:\n    // Call before begin() to indicate how much work is\n    // anticipated.\n    // numTasks is the number of tasks that will be added\n    // via addTask.\n    void addAnticipatedWork(ui32 work) = delete;\n    void addAnticipatedWork(ui32 work, ui32 numTasks) {\n#ifdef DEBUG\n        if (m_glRPCs) throw 380;\n#endif\n        m_totalWork += work;\n        m_numTasks += numTasks;\n    }\n\n    // If using any GL RPCs, be sure to call on GL thread\n    size_t processRequests(size_t maxRequests) {\n        return rpcManager.processRequests(maxRequests);\n    }\n\n    // Call this after all anticipated work is added, and before\n    // any tasks are added.\n    void begin() {\n        m_glRPCs = new vcore::GLRPC[m_numTasks];\n    }\n\n    // It is important that tasks added have been anticipated with\n    // addAnticipatedWork\n    template<typename F>\n    vcore::GLRPC& addTask(F f, bool blockUntilFinished) {\n#ifdef DEBUG\n        if (m_freeTask > m_numTasks) throw 381;\n#endif\n        vcore::GLRPC& rpc = m_glRPCs[m_freeTask++];\n        rpc.set(f);\n        rpcManager.invoke(&rpc, blockUntilFinished);\n        return rpc;\n    }\n\n    f32 getPercentComplete() const {\n        return (f32)m_workFinished / (f32)m_totalWork;\n    }\n    bool isWorkComplete() const {\n        return m_workFinished >= m_totalWork;\n    }\n\n    void blockUntilFinished() {\n        if (m_freeTask) m_glRPCs[m_freeTask - 1].block();\n    }\n\n    // Call this when work is completed to free memory used by GLRPCs.\n    void end() {\n        delete[] m_glRPCs;\n        m_glRPCs = nullptr;\n        m_numTasks = 0;\n        m_freeTask = 0;\n        resetWork();\n    }\nprotected:\n    vcore::GLRPC* m_glRPCs = nullptr;\n    ui32 m_numTasks = 0;\n    volatile ui32 m_freeTask = 0;\n};\n\n// For when the number of tasks might change\nclass DynamicLoadContext : public LoadContext {\npublic:\n    void resetWork() {\n        m_totalWork = 0;\n        m_workFinished = 0;\n    }\n\n    // If using any GL RPCs, be sure to call on GL thread\n    size_t processRequests(size_t maxRequests) {\n        return rpcManager.processRequests(maxRequests);\n    }\n\n    // It is important that tasks added have been anticipated with\n    // addAnticipatedWork\n    template<typename F>\n    vcore::GLRPC& addTask(F f, bool blockUntilFinished) {\n        m_glRPCs.emplace_back();\n        vcore::GLRPC& rpc = m_glRPCs.back();\n        rpc.set(f);\n        rpcManager.invoke(&rpc, blockUntilFinished);\n        return rpc;\n    }\n\n    f32 getPercentComplete() const {\n        return (f32)m_workFinished / (f32)m_totalWork;\n    }\n    bool isWorkComplete() const {\n        return m_workFinished >= m_totalWork;\n    }\n\n    void blockUntilFinished() {\n        m_glRPCs.back().block();\n    }\n\n    // Call this when work is completed to free memory used by GLRPCs.\n    void clearTasks() {\n        std::list<vcore::GLRPC>().swap(m_glRPCs);\n    }\n\nprotected:\n    std::list<vcore::GLRPC> m_glRPCs;\n};\n\n#endif // LoadContext_h__\n"
  },
  {
    "path": "SoA/LoadMonitor.cpp",
    "content": "#include \"stdafx.h\"\n#include \"LoadMonitor.h\"\n\nLoadMonitor::LoadMonitor() :\n_lock(),\n_completionCondition() {\n    // Empty\n}\nLoadMonitor::~LoadMonitor() {\n    if (_internalTasks.size() > 0) {\n        for (ILoadTask* t : _internalTasks) {\n            if (t) delete t;\n        }\n    }\n    for (auto& t : _internalThreads) {\n        t.detach();\n    }\n}\n\nvoid LoadMonitor::addTask(nString name, ILoadTask* task) {\n    _tasks.emplace(name, task);\n}\nbool LoadMonitor::isTaskFinished(nString task) {\n    _lock.lock();\n    bool state = isFinished(task);\n    _lock.unlock();\n    return state;\n}\n\nbool LoadMonitor::isFinished(nString task) {\n    auto kvp = _tasks.find(task);\n    if (kvp == _tasks.end()) {\n        fprintf(stderr, \"LoadMonitor Warning: dependency %s does not exist\\n\", task.c_str());\n        return false;\n    }\n    return kvp->second->isFinished();\n}\nbool LoadMonitor::canStart(nString task) {\n    // Check that the dependency exists\n    auto kvp = _tasks.find(task);\n    if (kvp == _tasks.end()) {\n        fprintf(stderr, \"LoadMonitor Warning: task %s does not exist\\n\", task.c_str());\n        return false;\n    }\n    // Check all dependencies\n    for (auto& dep : kvp->second->dependencies) {\n        if (!isFinished(dep)) {\n            return false;\n        }\n    }\n    return true;\n}\n\nvoid LoadMonitor::start() {\n    LoadMonitor* monitor = this;\n    for (auto& kvp : _tasks) {\n        ILoadTask* task = kvp.second;\n        nString name = kvp.first;\n        _internalThreads.emplace_back([=] () {\n            // Wait For Dependencies To Complete\n            std::unique_lock<std::mutex> uLock(monitor->_lock);\n            _completionCondition.wait(uLock, [=] {\n#ifdef DEBUG\n                printf(\"CHECK: %s\\r\\n\", name.c_str());\n#endif\n                return monitor->canStart(name);\n            });\n            uLock.unlock();\n\n#ifdef DEBUG\n            printf(\"BEGIN: %s\\r\\n\", name.c_str());\n            task->doWork();\n            printf(\"END: %s\\r\\n\", name.c_str());\n#else\n            task->doWork();\n#endif // DEBUG\n\n            // Notify That This Task Is Completed\n            uLock.lock();\n            _completionCondition.notify_all();\n            uLock.unlock();\n        });\n    }\n}\nvoid LoadMonitor::wait() {\n    // Wait for all threads to complete\n    for (auto& t : _internalThreads) {\n        t.join();\n        t.detach();\n    }\n\n    _internalThreads.clear();\n\n    // Free all tasks\n    for (ILoadTask* t : _internalTasks) delete t;\n    _internalTasks.clear();\n}\n\nvoid LoadMonitor::setDep(nString name, nString dep) {\n    // Check that the task exists\n    auto kvp = _tasks.find(name);\n    if (kvp == _tasks.end()) {\n        fprintf(stderr, \"LoadMonitor Warning: Task %s doesn't exist.\\n\",name.c_str());\n        return;\n    }\n\n    // Check that the dependency exists\n    auto dvp = _tasks.find(dep);\n    if (dvp == _tasks.end()) {\n        fprintf(stderr, \"LoadMonitor Warning: Dependency %s doesn't exist.\\n\", dep.c_str());\n        return;\n    }\n\n    // Add the dependency\n    kvp->second->dependencies.insert(dep);\n}\n\n\n"
  },
  {
    "path": "SoA/LoadMonitor.h",
    "content": "#pragma once\n\n#include <condition_variable>\n#include <unordered_map>\n#include <unordered_set>\n#include <thread>\n#include <Vorb/types.h>\n\n// Interface For A Loading Task\nclass ILoadTask {\npublic:\n    ILoadTask()\n        : _isFinished(false) {\n        // Empty\n    }\n    virtual ~ILoadTask(){}\n\n    bool isFinished() const {\n        return _isFinished;\n    }\n\n    virtual void load() = 0;\n    void doWork() {\n        load();\n        _isFinished = true;\n    }\n\n    std::unordered_set<nString> dependencies;\nprivate:\n    // Loading State\n    volatile bool _isFinished;\n};\n\n// Loading Task Closure Wrapper\ntemplate<typename F>\nclass LoadFunctor : public ILoadTask {\npublic:\n    LoadFunctor() {\n        // Empty\n    }\n    LoadFunctor(F& f) \n        : _f(f) {\n        // Empty\n    }\n\n    void load() {\n        // Call The Closure\n        _f();\n    }\nprivate:\n    F _f;\n};\n\n// Make Use Of Compiler Type Inference For Anonymous Type Closure Wrapper\ntemplate<typename F>\ninline ILoadTask* makeLoader(F f) {\n    return new LoadFunctor<F>(f);\n}\n\nclass LoadMonitor {\npublic:\n    LoadMonitor();\n    ~LoadMonitor();\n\n    // Add A Task To This List (No Copy Or Delete Will Be Performed On Task Pointer)\n    void addTask(nString name, ILoadTask* task);\n    template<typename F>\n    void addTaskF(nString name, F taskF) {\n        ILoadTask* t = makeLoader(taskF);\n        _internalTasks.push_back(t);\n        addTask(name, t);\n    }\n    \n    // Make A Loading Task Dependant On Another (Blocks Until Dependency Completes)\n    void setDep(nString name, nString dep);\n\n    // Fires Up Every Task In A Separate Thread\n    void start();\n    // Blocks On Current Thread Until All Child Threads Have Completed\n    void wait();\n\n    // Checks If A Task Is Finished\n    bool isTaskFinished(nString task);\nprivate:\n    // Is A Task Finished (False If Task Does Not Exist\n    bool isFinished(nString task);\n    // Check Dependencies Of A Task To See If It Can Begin\n    bool canStart(nString task);\n\n    // Tasks Mapped By Name\n    std::unordered_map<nString, ILoadTask*> _tasks;\n    \n    // Thread For Each Task\n    std::vector<std::thread> _internalThreads;\n\n    // Functor Wrapper Tasks That Must Be Deallocated By This Monitor\n    std::vector<ILoadTask*> _internalTasks;\n\n    // Monitor Lock\n    std::mutex _lock;\n    std::condition_variable _completionCondition;\n};"
  },
  {
    "path": "SoA/LoadTaskBlockData.h",
    "content": "#pragma once\n#include \"BlockPack.h\"\n#include \"BlockLoader.h\"\n#include \"BlockTextureLoader.h\"\n#include \"BlockTexturePack.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"LoadContext.h\"\n#include \"LoadMonitor.h\"\n\n#include <Vorb/io/IOManager.h>\n\n// This is hacky and temporary, it does way to much\nclass LoadTaskBlockData : public ILoadTask {\npublic:\n    LoadTaskBlockData(BlockPack* blockPack, BlockTextureLoader* loader, StaticLoadContext* context) :\n        blockPack(blockPack), loader(loader), context(context) {\n        context->addAnticipatedWork(50, 0);\n    }\n\n    virtual void load() {\n\n        loader->loadTextureData();\n\n        // TODO(Ben): Put in state\n        vio::IOManager iom;\n        iom.setSearchDirectory(\"Data/Blocks/\");\n        // Load in .yml\n        if (!BlockLoader::loadBlocks(iom, blockPack)) {\n            pError(\"Failed to load Data/Blocks/BlockData.yml\");\n            exit(123456);\n        }\n        context->addWorkCompleted(40);\n\n        for (size_t i = 0; i < blockPack->size(); i++) {\n            Block& b = blockPack->operator[](i);\n            if (b.active) {\n                loader->loadBlockTextures(b);\n            }\n        }\n        // Set the none textures so we dont get a crash later\n        Block& b = blockPack->operator[](\"none\");\n        for (int i = 0; i < 6; i++) {\n            b.textures[i] = loader->getTexturePack()->getDefaultTexture();\n        }\n        context->addWorkCompleted(10);\n\n\n        // Uncomment to Save in .yml\n        BlockLoader::saveBlocks(\"Data/Blocks/SavedBlockData.yml\", blockPack);\n\n        //{ // For use in pressure explosions\n        //    Block visitedNode = Blocks[0];\n        //    visitedNode.name = \"Visited Node\";\n        //    Blocks.append(&visitedNode, 1);\n        //    VISITED_NODE = Blocks[\"Visited Node\"].ID;\n        //}\n\n    }\n    BlockPack* blockPack;\n    BlockTextureLoader* loader;\n    StaticLoadContext* context;\n};\n"
  },
  {
    "path": "SoA/LoadTaskGameManager.h",
    "content": "#pragma once\n#include <SDL2/SDL.h>\n\n#include \"GameManager.h\"\n#include \"InputMapper.h\"\n#include \"LoadMonitor.h\"\n\n// Sample Dependency Task\nclass LoadTaskGameManager : public ILoadTask {\n    virtual void load() {\n        GameManager::initializeSystems();\n        GameManager::registerTexturesForLoad();\n    }\n};"
  },
  {
    "path": "SoA/LoadTaskStarSystem.h",
    "content": "#pragma once\n#include \"LoadMonitor.h\"\n#include \"SpaceSystem.h\"\n\n#include \"SoaEngine.h\"\n\n// Sample Dependency Task\nclass LoadTaskStarSystem : public ILoadTask {\n    friend class MainMenuLoadScreen;\n\n    LoadTaskStarSystem(const nString& filePath, SoaState* state) :\n        filePath(filePath),\n        soaState(state) {\n        // Empty\n    }\n    virtual void load() {\n        SoaEngine::loadSpaceSystem(soaState, filePath);\n    }\n\n    nString filePath;\n    SoaState* soaState;\n};"
  },
  {
    "path": "SoA/LoadTaskTextures.h",
    "content": "#pragma once\n#include \"LoadMonitor.h\"\n#include \"GameManager.h\"\n#include \"SoaOptions.h\"\n#include \"PlanetGenData.h\"\n\n// TODO(Ben): Multiple loader threads\nclass LoadTaskTextures : public ILoadTask {\n    virtual void load() {\n      \n        //load the texture pack\n        // GameManager::texturePackLoader->setColorMaps(&PlanetGenData::colorMaps);\n        // GameManager::texturePackLoader->loadAllTextures(\"Textures/TexturePacks/\" + soaOptions.getStringOption(\"Texture Pack\").value + \"/\");\n    }\n};"
  },
  {
    "path": "SoA/MTRenderState.h",
    "content": "///\n/// MTRenderState.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 22 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Render state that needs to be cloned for multi-threading\n/// to prevent inaccuracies.\n///\n\n#pragma once\n\n#ifndef MTRenderState_h__\n#define MTRenderState_h__\n\n#include \"Chunk.h\" // for DebugChunkData\n\n#include \"GameSystemComponents.h\"\n\n#include <Vorb/ecs/ECS.h>\n#include <map>\n\nstruct DebugChunkData {\n    f64v3 voxelPosition;\n    ChunkGenLevel genLevel;\n};\n\n/// Not every bit of render state needs to be in MTRenderState. Only things\n/// that are sensitive, such as fast moving planets and the camera.\nstruct MTRenderState {\n    f64q spaceCameraOrientation; ///< Orientation in space\n    f64v3 spaceCameraPos; ///< Position in space, relative to parent body\n    bool hasVoxelPos;\n    HeadComponent playerHead;\n    VoxelPositionComponent playerPosition;\n    std::map<vecs::EntityID, f64v3> spaceBodyPositions; ///< Space entity positions\n    std::vector<DebugChunkData> debugChunkData;\n};\n\n#endif // MTRenderState_h__\n"
  },
  {
    "path": "SoA/MTRenderStateManager.cpp",
    "content": "#include \"stdafx.h\"\n#include \"MTRenderStateManager.h\"\n\n// Increments i in modulo 3 for triple buffering\nvoid incrementMod3(OUT int& i) {\n    i = (i + 1) % 3;\n}\n\nMTRenderState* MTRenderStateManager::getRenderStateForUpdate() {\n    std::lock_guard<std::mutex> lock(m_lock);\n    // Get the next free state\n    incrementMod3(m_updating);\n    if (m_updating == m_rendering) {\n        incrementMod3(m_updating);\n    }\n    return &m_renderState[m_updating];\n}\n\nvoid MTRenderStateManager::finishUpdating() {\n    std::lock_guard<std::mutex> lock(m_lock);\n    // Mark the currently updating buffer as the last updated\n    m_lastUpdated = m_updating;\n}\n\nconst MTRenderState* MTRenderStateManager::getRenderStateForRender() {\n    std::lock_guard<std::mutex> lock(m_lock);\n    // If we haven't updated again, return the same one\n    if (m_rendering == m_lastUpdated) return &m_renderState[m_rendering];\n    // Render the last updated state\n    m_rendering = m_lastUpdated;\n    return &m_renderState[m_rendering];\n}\n"
  },
  {
    "path": "SoA/MTRenderStateManager.h",
    "content": "///\n/// MTRenderStateManager.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 22 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Manages the updating and access of triple buffered\n/// render state on the render and update threads\n///\n\n#pragma once\n\n#ifndef MTRenderStateManager_h__\n#define MTRenderStateManager_h__\n\n#include \"MTRenderState.h\"\n#include <mutex>\n\nclass MTRenderStateManager {\npublic:\n    /// Gets the state for updating. Only call once per frame.\n    MTRenderState* getRenderStateForUpdate();\n    /// Marks state as finished updating. Only call once per frame,\n    /// must call for every call to getRenderStateForUpdate.\n    void finishUpdating();\n    /// Gets the state for rendering. Only call once per frame.\n    const MTRenderState* getRenderStateForRender();\nprivate:\n    int m_updating = 0; ///< Currently updating state\n    int m_lastUpdated = 0; ///< Most recently updated state\n    int m_rendering = 0; ///< Currently rendering state\n    MTRenderState m_renderState[3]; ///< Triple-buffered state\n    std::mutex m_lock;\n};\n\n#endif // MTRenderStateManager_h__\n"
  },
  {
    "path": "SoA/MainMenuLoadScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"MainMenuLoadScreen.h\"\n\n#include <Vorb/colors.h>\n#include <Vorb/graphics/GLStates.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/graphics/SpriteBatch.h>\n\n#include \"App.h\"\n#include \"BlockPack.h\"\n#include \"ChunkMeshManager.h\"\n#include \"DebugRenderer.h\"\n#include \"GameManager.h\"\n#include \"InputMapper.h\"\n#include \"Inputs.h\"\n#include \"LoadTaskGameManager.h\"\n#include \"LoadTaskStarSystem.h\"\n#include \"MainMenuScreen.h\"\n#include \"MusicPlayer.h\"\n#include \"SoaFileSystem.h\"\n#include \"SoAState.h\"\n\nconst color4 LOAD_COLOR_TEXT(205, 205, 205, 255);\nconst color4 LOAD_COLOR_BG_LOADING(105, 5, 5, 255);\nconst color4 LOAD_COLOR_BG_FINISHED(25, 105, 5, 255);\n\nMainMenuLoadScreen::MainMenuLoadScreen(const App* app, CommonState* state, MainMenuScreen* mainMenuScreen) :\nIAppScreen<App>(app),\nm_commonState(state),\nm_mainMenuScreen(mainMenuScreen) {\n    // Empty\n}\n\ni32 MainMenuLoadScreen::getNextScreen() const {\n    return m_app->scrMainMenu->getIndex();\n}\ni32 MainMenuLoadScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid MainMenuLoadScreen::build() {\n    m_env.init();\n\n#if defined(__GNUC__) && !defined(__clang__)\n#    pragma GCC diagnostic push\n#    pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n#endif\n    m_env.addValue(\"WindowWidth\",  static_cast<f64>(m_game->getWindow().getWidth()));\n    m_env.addValue(\"WindowHeight\", static_cast<f64>(m_game->getWindow().getHeight()));\n\n    m_env.run(nString(\"Data/Logos/Vorb/ScreenUpdate.lua\"));\n    m_vorbScreenDuration   = m_env.template getScriptDelegate<f64>(\"VorbMaxDuration\")();\n    m_fUpdateVorbPosition  = m_env.template getScriptDelegate<f32v2, f64, nString>(\"VorbPositionAtTime\");\n    m_fUpdateVorbColor     = m_env.template getScriptDelegate<color4, f64, nString>(\"VorbColorAtTime\");\n    m_fUpdateVorbBackColor = m_env.template getScriptDelegate<color4, f64>(\"VorbBackgroundColor\");\n\n    m_env.run(nString(\"Data/Logos/Regrowth/ScreenUpdate.lua\"));\n    m_regrowthScreenDuration   = m_env.template getScriptDelegate<f64>(\"RegrowthMaxDuration\")();\n    m_fUpdateRegrowthPosition  = m_env.template getScriptDelegate<f32v2, f64, nString>(\"RegrowthPositionAtTime\");\n    m_fUpdateRegrowthColor     = m_env.template getScriptDelegate<color4, f64, nString>(\"RegrowthColorAtTime\");\n    m_fUpdateRegrowthBackColor = m_env.template getScriptDelegate<color4, f64>(\"RegrowthBackgroundColor\");\n    m_regrowthScale            = m_env.template getScriptDelegate<f32>(\"RegrowthScale\")();\n#if defined(__GNUC__) && !defined(__clang__)\n#    pragma GCC diagnostic pop\n#endif\n    { // Load all textures\n        const cString vorbTexturePaths[VORB_NUM_TEXTURES] = {\n            \"Data/Logos/Vorb/V.png\",\n            \"Data/Logos/Vorb/O.png\",\n            \"Data/Logos/Vorb/R.png\",\n            \"Data/Logos/Vorb/B.png\",\n            \"Data/Logos/Vorb/CubeLeft.png\",\n            \"Data/Logos/Vorb/CubeRight.png\",\n            \"Data/Logos/Vorb/CubeTop.png\"\n        };\n        vg::ImageIO imageIO;\n        for (size_t i = 0; i < VORB_NUM_TEXTURES; i++) {\n            vg::Texture& tex = m_vorbTextures[i];\n\n            // Load file\n            vg::ScopedBitmapResource bmp(imageIO.load(vorbTexturePaths[i]));\n            tex.width = bmp.width;\n            tex.height = bmp.height;\n\n            // Create GPU texture\n            glGenTextures(1, &tex.id);\n            glBindTexture(GL_TEXTURE_2D, tex.id);\n            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bmp.data);\n            glBindTexture(GL_TEXTURE_2D, 0);\n        }\n        const cString regrowthTexturePaths[REGROWTH_NUM_TEXTURES] = {\n            \"Data/Logos/Regrowth/Regrowth.png\",\n            \"Data/Logos/Regrowth/Studios.png\"\n        };\n        for (size_t i = 0; i < REGROWTH_NUM_TEXTURES; i++) {\n            vg::Texture& tex = m_regrowthTextures[i];\n\n            // Load file\n            vg::ScopedBitmapResource bmp(imageIO.load(regrowthTexturePaths[i]));\n            tex.width = bmp.width;\n            tex.height = bmp.height;\n\n            // Create GPU texture\n            glGenTextures(1, &tex.id);\n            glBindTexture(GL_TEXTURE_2D, tex.id);\n            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bmp.data);\n            glBindTexture(GL_TEXTURE_2D, 0);\n        }\n    }\n}\nvoid MainMenuLoadScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid MainMenuLoadScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    SoaFileSystem fs;\n    fs.init();\n    MusicPlayer mp;\n    mp.refreshLists(fs);\n\n    SoaEngine::initState(m_commonState->state);\n\n    // Make LoadBar Resources\n    m_sb = new vg::SpriteBatch(true, true);\n    m_sf = new vg::SpriteFont();\n    m_sf->init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n\n    // Add Tasks Here\n    addLoadTask(\"GameManager\", \"Core Systems\", new LoadTaskGameManager);\n\n    addLoadTask(\"SpaceSystem\", \"SpaceSystem\", new LoadTaskStarSystem(\"StarSystems/Trinity\", m_commonState->state));\n    m_monitor.setDep(\"SpaceSystem\", \"GameManager\");\n\n    m_mainMenuScreen->m_renderer.init(m_commonState->window, m_commonState->loadContext, m_mainMenuScreen, m_commonState);\n    m_mainMenuScreen->m_renderer.hook();\n    m_commonState->loadContext.begin();\n    m_mainMenuScreen->m_renderer.load(m_commonState->loadContext);\n\n    // Start the tasks\n    m_monitor.start();\n\n    m_isSkipDetected = false;\n    m_timer = 0.0;\n    vui::InputDispatcher::key.onKeyDown += makeDelegate(this, &MainMenuLoadScreen::onKeyPress);\n}\nvoid MainMenuLoadScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_sf->dispose();\n    delete m_sf;\n    m_sf = nullptr;\n\n    m_sb->dispose();\n    delete m_sb;\n    m_sb = nullptr;\n\n    for (ui32 i = 0; i < m_loadTasks.size(); i++) {\n        // Free memory\n        delete m_loadTasks[i];\n        m_loadTasks[i] = nullptr;\n    }\n    std::vector<ILoadTask*>().swap(m_loadTasks);\n\n    // Restore default rasterizer state\n    vg::RasterizerState::CULL_CLOCKWISE.set();\n\n    // Free textures\n    for (size_t i = 0; i < VORB_NUM_TEXTURES; i++) glDeleteTextures(1, &m_vorbTextures[i].id);\n    for (size_t i = 0; i < REGROWTH_NUM_TEXTURES; i++) glDeleteTextures(1, &m_regrowthTextures[i].id);\n\n    vui::InputDispatcher::key.onKeyDown -= makeDelegate(this, &MainMenuLoadScreen::onKeyPress);\n}\n\nvoid MainMenuLoadScreen::update(const vui::GameTime& gameTime) {\n    // Increment elapsed time\n    m_timer += gameTime.elapsed;\n    if (m_isOnVorb && m_timer > m_vorbScreenDuration) {\n        m_timer = 0.0f;\n        m_isOnVorb = false;\n    }\n\n    // Perform OpenGL calls\n    m_commonState->loadContext.processRequests(1);\n\n    // End condition\n    if (m_mainMenuScreen->m_renderer.isLoaded() && m_monitor.isTaskFinished(\"SpaceSystem\") && (m_isSkipDetected || (!m_isOnVorb && m_timer > m_regrowthScreenDuration))) {\n        m_commonState->loadContext.end();\n        m_state = vui::ScreenState::CHANGE_NEXT;\n    }\n}\nvoid MainMenuLoadScreen::draw(const vui::GameTime&) {\n    static const cString vorbTextureNames[VORB_NUM_TEXTURES] = {\n        \"V\", \"O\", \"R\", \"B\", \"CubeLeft\", \"CubeRight\", \"CubeTop\"\n    };\n    static const cString regrowthTextureNames[REGROWTH_NUM_TEXTURES] = {\n        \"Regrowth\", \"Studios\"\n    };\n    const vui::GameWindow& w = m_game->getWindow();\n\n    // Clear State For The Screen\n    color4 clearColor;\n    if (m_isOnVorb) {\n        clearColor = m_fUpdateVorbBackColor(m_timer);\n    } else {\n        clearColor = m_fUpdateRegrowthBackColor(m_timer);\n    }\n    glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);\n\n    glClearDepth(1.0);\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    // Draw vorb logo\n    // Update the window size\n    f32v2 windowSize(w.getWidth(), w.getHeight());\n    m_env.addValue(\"WindowWidth\",  windowSize.x);\n    m_env.addValue(\"WindowHeight\", windowSize.y);\n\n    // Render each texture\n    m_sb->begin();\n    f32v2 uvTile(0.999999f, 0.999999f);\n    // TODO: Fix this.\n    if (m_isOnVorb) {\n       for (size_t i = 0; i < VORB_NUM_TEXTURES; i++) {\n           f32v2 pos   = m_fUpdateVorbPosition(m_timer, nString(vorbTextureNames[i]));\n           color4 color = m_fUpdateVorbColor(m_timer, nString(vorbTextureNames[i]));          \n           m_sb->draw(m_vorbTextures[i].id, nullptr, &uvTile, pos, f32v2(m_vorbTextures[i].width, m_vorbTextures[i].height), color);\n       }\n    } else {\n       if (m_timer <= m_regrowthScreenDuration) {\n           for (size_t i = 0; i < REGROWTH_NUM_TEXTURES; i++) {\n               f32v2 pos   = m_fUpdateRegrowthPosition(m_timer, nString(regrowthTextureNames[i]));\n               color4 color = m_fUpdateRegrowthColor(m_timer, nString(regrowthTextureNames[i]));\n               m_sb->draw(m_regrowthTextures[i].id, nullptr, &uvTile, pos, f32v2(m_regrowthTextures[i].width, m_regrowthTextures[i].height) * m_regrowthScale, color);\n           }\n       } else {\n            // Animated loading message. TODO(Ben): Replace with progress bar\n            int it = (int)m_timer % 3;\n            if (it == 0) {\n                m_sb->drawString(m_sf, \"Loading.\", f32v2(w.getWidth() - m_sf->measure(\"Loading\").x * 0.5, w.getHeight()) / 2.0f, f32v2(1.0), color::White, vg::TextAlign::LEFT);\n            } else if (it == 1) {\n                m_sb->drawString(m_sf, \"Loading..\", f32v2(w.getWidth() - m_sf->measure(\"Loading\").x * 0.5, w.getHeight()) / 2.0f, f32v2(1.0), color::White, vg::TextAlign::LEFT);\n            } else {\n                m_sb->drawString(m_sf, \"Loading...\", f32v2(w.getWidth() - m_sf->measure(\"Loading\").x * 0.5, w.getHeight()) / 2.0f, f32v2(1.0), color::White, vg::TextAlign::LEFT);\n            }\n        }     \n    }\n    m_sb->end();\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    m_sb->render(windowSize, &vg::SamplerState::LINEAR_CLAMP);\n\n    // Draw progress\n    f32 progress = m_commonState->loadContext.getPercentComplete();\n    static f32 maxw = 48.0f;\n    static f32 alpha = 1.0f;\n    if (alpha > 0.0f) {\n        const f32 border = 2.0f;\n        const f32v2 pos(w.getWidth() - maxw * 2.0f, w.getHeight() - maxw * 2.0f);\n\n        if (progress >= 1.0f) {\n            alpha -= 0.02f;\n            if (alpha < 0.0f) alpha = 0.0f;\n        }\n        f32 width = alpha * maxw;\n        m_sb->begin();\n        f32v2 size = f32v2(width - border * 2.0f);\n        m_sb->draw(0, pos - size / 2.0f, size, color::Transparent, 0.1f);\n        size = f32v2(width);\n        m_sb->draw(0, pos - size / 2.0f, size, color4(169u, 169u, 169u, (ui8)(alpha * 255.0f)), 0.1f);\n        size = f32v2(progress * width);\n        m_sb->draw(0, pos - size / 2.0f, size, color4(16u, 190u, 239u, ui8(alpha * 255.0f)));\n        m_sb->end(vg::SpriteSortMode::NONE);\n        m_sb->render(f32v2(w.getWidth(), w.getHeight()), nullptr, &vg::DepthState::FULL);\n    }\n    checkGlError(\"LoadScreen::draw()\");\n    \n}\n\nvoid MainMenuLoadScreen::addLoadTask(const nString& name, const cString loadText VORB_MAYBE_UNUSED, ILoadTask* task) {\n    // Add the load task to the monitor\n    m_loadTasks.push_back(task);\n    m_monitor.addTask(name, m_loadTasks.back());\n}\n\nvoid MainMenuLoadScreen::onKeyPress(Sender, const vui::KeyEvent& e) {\n    switch (e.keyCode) {\n        case VKEY_RETURN:\n        case VKEY_ESCAPE:\n        case VKEY_SPACE:\n            m_isSkipDetected = true;\n            break;\n        default:\n            break;\n    }\n}\n"
  },
  {
    "path": "SoA/MainMenuLoadScreen.h",
    "content": "#pragma once\n\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/Random.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/Texture.h>\n#include <Vorb/script/lua/Environment.h>\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/ui/InputDispatcher.h>\n\n#include \"LoadMonitor.h\"\n#include \"LoadBar.h\"\n\nclass App;\nclass MainMenuScreen;\nstruct CommonState;\nDECL_VG(class SpriteBatch; class SpriteFont);\n\n#define VORB_NUM_TEXTURES 7\n#define REGROWTH_NUM_TEXTURES 2\n\nclass MainMenuLoadScreen : public vui::IAppScreen<App> {\npublic:\n    MainMenuLoadScreen(const App* app, CommonState* state, MainMenuScreen* mainMenuScreen);\n\n    virtual i32 getNextScreen() const;\n    virtual i32 getPreviousScreen() const;\n\n    virtual void build();\n    virtual void destroy(const vui::GameTime& gameTime);\n\n    virtual void onEntry(const vui::GameTime& gameTime);\n    virtual void onExit(const vui::GameTime& gameTime);\n\n    virtual void update(const vui::GameTime& gameTime);\n    virtual void draw(const vui::GameTime& gameTime);\n\nprivate:\n    void onKeyPress(Sender, const vui::KeyEvent& e);\n    void addLoadTask(const nString& name, const cString loadText, ILoadTask* task);\n\n    // Game state\n    CommonState* m_commonState = nullptr;\n    MainMenuScreen* m_mainMenuScreen = nullptr;\n\n    // Visualization Of Loading Tasks\n    vg::SpriteBatch* m_sb = nullptr;\n    vg::SpriteFont* m_sf = nullptr;\n\n    // Loading Tasks\n    LoadMonitor m_monitor;\n    std::vector<ILoadTask*> m_loadTasks;\n\n    // Vars for logos\n    f64  m_timer;\n    f64  m_vorbScreenDuration;\n    f64  m_regrowthScreenDuration;\n    f32  m_regrowthScale;\n    bool m_isSkipDetected;\n\n    vg::Texture m_vorbTextures[VORB_NUM_TEXTURES]; ///< 7 textures for the letters and cube\n    vg::Texture m_regrowthTextures[REGROWTH_NUM_TEXTURES]; ///< 2 Textures for Regrowth Studios\n\n    vscript::lua::Environment      m_env;\n    Delegate<f32v2, f64, nString>  m_fUpdateVorbPosition; ///< f32v2 (f64 totalTime, nString texture)\n    Delegate<color4, f64, nString> m_fUpdateVorbColor; ///< f32v4 (f64 totalTime, nString texture)\n    Delegate<color4, f64>          m_fUpdateVorbBackColor;///< f32v4 (f64 totalTime)\n    Delegate<f32v2, f64, nString>  m_fUpdateRegrowthPosition; ///< f32v2 (f64 totalTime, nString texture)\n    Delegate<color4, f64, nString> m_fUpdateRegrowthColor; ///< f32v4 (f64 totalTime, nString texture)\n    Delegate<color4, f64>          m_fUpdateRegrowthBackColor;///< f32v4 (f64 totalTime)\n\n    bool m_isOnVorb = true;\n};"
  },
  {
    "path": "SoA/MainMenuRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"MainMenuRenderer.h\"\n\n#include <Vorb/graphics/TextureCache.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/io/FileOps.h>\n#include <Vorb/utils.h>\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/ui/GameWindow.h>\n\n#include \"CommonState.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"HdrRenderStage.h\"\n#include \"MainMenuScreen.h\"\n#include \"MainMenuScriptedUI.h\"\n#include \"SoaOptions.h\"\n#include \"SoAState.h\"\n#include \"soaUtils.h\"\n#include \"BloomRenderStage.h\"\n\nvoid MainMenuRenderer::init(vui::GameWindow* window, StaticLoadContext& context,\n                            MainMenuScreen* mainMenuScreen, CommonState* commonState) {\n    m_window = window;\n    m_mainMenuScreen = mainMenuScreen;\n    m_commonState = commonState;\n    m_state = m_commonState->state;\n    vui::InputDispatcher::window.onResize += makeDelegate(this, &MainMenuRenderer::onWindowResize);\n\n    // TODO(Ben): Dis is bad mkay\n    m_viewport = f32v4(0, 0, m_window->getWidth(), m_window->getHeight());\n\n    m_mainMenuUI = &m_mainMenuScreen->m_ui;\n    // Add anticipated work\n    context.addAnticipatedWork(3, 3);\n\n    // Init render stages\n    m_commonState->stages.skybox.init(window, context);\n    m_commonState->stages.spaceSystem.init(window, context);\n    m_commonState->stages.hdr.init(window, context);\n    stages.colorFilter.init(window, context);\n    stages.exposureCalc.init(window, context);\n\n    stages.bloom.init(window, context);\n    stages.bloom.setParams();\n    stages.bloom.setActive(true);\n\n\n    // TODO(Cristian): This needs to be upgraded.\n    // Generate terrain patch indices\n    TerrainPatchMesher::generateIndices();\n}\n\nvoid MainMenuRenderer::dispose(StaticLoadContext& context) {\n    vui::InputDispatcher::window.onResize -= makeDelegate(this, &MainMenuRenderer::onWindowResize);\n\n    // Kill the builder\n    if (m_loadThread) {\n        delete m_loadThread;\n        m_loadThread = nullptr;\n    }\n    // TODO(Ben): Dispose common stages\n    stages.colorFilter.dispose(context);\n    stages.exposureCalc.dispose(context);\n    stages.bloom.dispose(context);\n\n    // Dispose of persistent rendering resources\n    m_hdrTarget.dispose();\n    m_swapChain.dispose();\n}\n\nvoid MainMenuRenderer::load(StaticLoadContext& context) {\n    m_isLoaded = false;\n\n\n\n    m_loadThread = new std::thread([&]() {\n        vcore::GLRPC so[4];\n        // size_t i = 0;\n\n        // Create the HDR target  \n        // Create the HDR target     \n        context.addTask([&](Sender, void*) {\n            Array<vg::GBufferAttachment> attachments;\n            vg::GBufferAttachment att[2];\n            // TODO(Ben): Don't think this is right.\n            // Color\n            att[0].format = vg::TextureInternalFormat::RGBA16F;\n            att[0].pixelFormat = vg::TextureFormat::RGBA;\n            att[0].pixelType = vg::TexturePixelType::UNSIGNED_BYTE;\n            att[0].number = 1;\n            // Normals\n            att[1].format = vg::TextureInternalFormat::RGBA16F;\n            att[1].pixelFormat = vg::TextureFormat::RGBA;\n            att[1].pixelType = vg::TexturePixelType::UNSIGNED_BYTE;\n            att[1].number = 2;\n            m_hdrTarget.setSize(m_window->getWidth(), m_window->getHeight());\n            m_hdrTarget.init(Array<vg::GBufferAttachment>(att, 2), vg::TextureInternalFormat::RGBA32F).initDepth();\n\n            if (soaOptions.get(OPT_MSAA).value.i > 0) {\n                glEnable(GL_MULTISAMPLE);\n            }\n            else {\n                glDisable(GL_MULTISAMPLE);\n            }\n            context.addWorkCompleted(1);\n        }, false);\n\n        // Create the swap chain for post process effects (HDR-capable)\n        context.addTask([&](Sender, void*) { \n            m_swapChain.init(m_window->getWidth(), m_window->getHeight(), vg::TextureInternalFormat::RGBA32F);\n            context.addWorkCompleted(1);\n        }, false);\n\n        // Create full-screen quad\n        context.addTask([&](Sender, void*) {\n            m_commonState->quad.init();\n            context.addWorkCompleted(1);\n        }, false);\n\n        // Load all the stages\n        m_commonState->stages.skybox.load(context);\n        m_commonState->stages.spaceSystem.load(context);\n        m_commonState->stages.hdr.load(context);\n        stages.colorFilter.load(context);\n        stages.exposureCalc.load(context);\n        stages.bloom.load(context);\n\n        context.blockUntilFinished();\n\n        m_isLoaded = true;\n    });\n    m_loadThread->detach();\n}\n\nvoid MainMenuRenderer::hook() {\n    m_commonState->stages.skybox.hook(m_state);\n    m_commonState->stages.spaceSystem.hook(m_state, &m_state->clientState.spaceCamera, nullptr);\n    m_commonState->stages.hdr.hook(&m_commonState->quad);\n    stages.colorFilter.hook(&m_commonState->quad);\n    stages.exposureCalc.hook(&m_commonState->quad, &m_hdrTarget, &m_viewport, 1024);\n    stages.bloom.hook(&m_commonState->quad);\n}\n\nvoid MainMenuRenderer::render() {\n    // Check for window resize\n    if (m_shouldResize) resize();\n\n    // Bind the FBO\n    m_hdrTarget.useGeometry();\n    // Clear depth buffer. Don't have to clear color since skybox will overwrite it\n    glClear(GL_DEPTH_BUFFER_BIT);\n\n    // Main render passes\n    m_commonState->stages.skybox.render(&m_state->clientState.spaceCamera);\n\n    // Check fore wireframe mode\n    if (m_wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n\n    m_commonState->stages.spaceSystem.setShowAR(m_showAR);\n    m_commonState->stages.spaceSystem.render(&m_state->clientState.spaceCamera);\n\n    // Restore fill\n    if (m_wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\n    f32v3 colorFilter(1.0);\n    // Color filter rendering\n    if (m_colorFilter != 0) {\n        switch (m_colorFilter) {\n        case 1:\n            colorFilter = f32v3(0.66f);\n            stages.colorFilter.setColor(f32v4(0.0, 0.0, 0.0, 0.33f)); break;\n        case 2:\n            colorFilter = f32v3(0.3f);\n            stages.colorFilter.setColor(f32v4(0.0, 0.0, 0.0, 0.66f)); break;\n        case 3:\n            colorFilter = f32v3(0.0f);\n            stages.colorFilter.setColor(f32v4(0.0, 0.0, 0.0, 0.9f)); break;\n        }\n        stages.colorFilter.render();\n    }\n\n    stages.exposureCalc.render();\n    // Move exposure towards target\n    static const f32 EXPOSURE_STEP = 0.005f;\n    stepTowards(soaOptions.get(OPT_HDR_EXPOSURE).value.f, stages.exposureCalc.getExposure(), EXPOSURE_STEP);\n\n    // Post processing\n    m_swapChain.reset(0, m_hdrTarget.getGeometryID(), m_hdrTarget.getGeometryTexture(0), soaOptions.get(OPT_MSAA).value.i > 0, false);\n\n    // TODO: More Effects?\n\n    // last effect should not swap swapChain\n    if (stages.bloom.isActive()) {\n        stages.bloom.render();\n    }\n\n    // Render last\n    glBlendFunc(GL_ONE, GL_ONE);\n    m_commonState->stages.spaceSystem.renderStarGlows(colorFilter);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    m_swapChain.swap();\n    m_swapChain.bindPreviousTexture(0);\n\n    // Draw to backbuffer for the last effect\n    m_swapChain.unuse(m_window->getWidth(), m_window->getHeight());\n    glDrawBuffer(GL_BACK);\n    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);\n\n    // original depth texture\n    m_hdrTarget.bindDepthTexture(1);\n    m_commonState->stages.hdr.render(&m_state->clientState.spaceCamera);\n\n    if (m_showUI) m_mainMenuUI->draw();\n\n    if (m_shouldScreenshot) dumpScreenshot();\n\n    // Check for errors, just in case\n    checkGlError(\"MainMenuRenderPipeline::render()\");\n}\n\nvoid MainMenuRenderer::onWindowResize(Sender, const vui::WindowResizeEvent& e) {\n    m_newDims = ui32v2(e.w, e.h);\n    m_shouldResize = true;\n}\n\nvoid MainMenuRenderer::resize() {\n    m_viewport.z = m_newDims.x;\n    m_viewport.w = m_newDims.y;\n\n    // TODO(Ben): Fix\n    /* m_hdrFrameBuffer->dispose();\n     delete m_hdrFrameBuffer;\n     m_swapChain->dispose();\n     delete m_swapChain;\n     initFramebuffer();*/\n\n    m_commonState->stages.spaceSystem.setViewport(m_newDims);\n    stages.exposureCalc.setFrameBuffer(&m_hdrTarget);\n\n    // Pretty sure we don't need to do this.\n    // m_mainMenuUI->setDimensions(f32v2(m_newDims));\n\n    m_shouldResize = false;\n}\n\nvoid MainMenuRenderer::dumpScreenshot() {\n    // Make screenshots directory\n    vio::buildDirectoryTree(\"Screenshots\");\n    // Take screenshot\n    dumpFramebufferImage(\"Screenshots/\", m_viewport);\n    m_shouldScreenshot = false;\n}\n"
  },
  {
    "path": "SoA/MainMenuRenderer.h",
    "content": "/// \n///  MainMenuRenderer.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the rendering pipeline for the main menu screen.\n///\n\n#pragma once\n\n#ifndef MainMenuRenderer_h__\n#define MainMenuRenderer_h__\n\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GLRenderTarget.h>\n#include <Vorb/graphics/RTSwapChain.hpp>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/GBuffer.h>\n\n#include \"ExposureCalcRenderStage.h\"\n#include \"SpaceSystemRenderStage.h\"\n#include \"ColorFilterRenderStage.h\"\n#include \"SkyboxRenderStage.h\"\n#include \"HdrRenderStage.h\"\n#include \"BloomRenderStage.h\"\n#include \"LoadContext.h\"\n\n/// Forward declarations\nclass Camera;\nclass MainMenuScreen;\nclass MainMenuScriptedUI;\nclass MainMenuSystemViewer;\nclass SpaceSystem;\nstruct CommonState;\nstruct SoaState;\nDECL_VUI(struct WindowResizeEvent; class GameWindow);\n\nclass MainMenuRenderer {\npublic:\n    /// Initializes the pipeline and passes dependencies\n    void init(vui::GameWindow* window, StaticLoadContext& context,\n              MainMenuScreen* mainMenuScreen, CommonState* commonState);\n\n    void hook();\n\n    // Is asynchronous. Check isLoaded\n    void load(StaticLoadContext& context);\n\n    void dispose(StaticLoadContext& context);\n\n    /// Renders the pipeline\n    void render();\n\n    void onWindowResize(Sender s, const vui::WindowResizeEvent& e);\n\n    void takeScreenshot() { m_shouldScreenshot = true; }\n\n    void setShowUI(bool showUI) { m_showUI = showUI; }\n    void toggleUI() { m_showUI = !m_showUI; }\n    void toggleAR() { m_showAR = !m_showAR; }\n    void toggleWireframe() { m_wireframe = !m_wireframe; }\n    void cycleColorFilter() { m_colorFilter++; if (m_colorFilter > 3) m_colorFilter = 0; }\n   \n    const volatile bool& isLoaded() const { return m_isLoaded; }\n\n    struct {    \n        ColorFilterRenderStage colorFilter;\n        ExposureCalcRenderStage exposureCalc;    \n        BloomRenderStage bloom;\n    } stages;\n\nprivate:\n    void resize();\n    void dumpScreenshot();\n\n    vui::GameWindow* m_window;\n    CommonState* m_commonState = nullptr;\n    SoaState* m_state = nullptr;\n    MainMenuScreen* m_mainMenuScreen = nullptr;\n\n    vg::GBuffer m_hdrTarget; ///< Framebuffer needed for the HDR rendering\n    vg::RTSwapChain<2> m_swapChain; ///< Swap chain of framebuffers used for post-processing\n    MainMenuScriptedUI* m_mainMenuUI; ///< The main menu UI\n\n    std::thread* m_loadThread = nullptr;\n    volatile bool m_isLoaded = false;\n\n    ui32v4 m_viewport; ///< Viewport to draw to\n    bool m_showUI = true;\n    bool m_showAR = true;\n    bool m_shouldScreenshot = false;\n    bool m_shouldResize = false;\n    bool m_wireframe = false;\n    ui32v2 m_newDims;\n    int m_colorFilter = 0;\n};\n\n#endif // MainMenuRenderer_h__\n"
  },
  {
    "path": "SoA/MainMenuScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"MainMenuScreen.h\"\n\n#include <Vorb/sound/SoundEngine.h>\n#include <Vorb/sound/SoundListener.h>\n\n#include \"AmbienceLibrary.h\"\n#include \"AmbiencePlayer.h\"\n#include \"App.h\"\n\n#include \"DebugRenderer.h\"\n#include \"Errors.h\"\n#include \"Frustum.h\"\n#include \"GameManager.h\"\n#include \"GamePlayScreen.h\"\n#include \"GameplayLoadScreen.h\"\n#include \"InputMapper.h\"\n#include \"Inputs.h\"\n#include \"MainMenuLoadScreen.h\"\n#include \"MainMenuScreen.h\"\n#include \"MainMenuSystemViewer.h\"\n#include \"SoaOptions.h\"\n#include \"SoAState.h\"\n#include \"SoaEngine.h\"\n#include \"SpaceSystem.h\"\n#include \"SpaceSystemUpdater.h\"\n#include \"TerrainPatch.h\"\n#include \"VoxelEditor.h\"\n\nMainMenuScreen::MainMenuScreen(const App* app, CommonState* state) :\n    IAppScreen<App>(app),\n    m_commonState(state),\n    m_soaState(state->state),\n    m_updateThread(nullptr),\n    m_threadRunning(false),\n    m_window(state->window) {\n    // Empty\n}\n\nMainMenuScreen::~MainMenuScreen() {\n    // Empty\n}\n\ni32 MainMenuScreen::getNextScreen() const {\n    return m_app->scrGameplayLoad->getIndex();\n}\n\ni32 MainMenuScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid MainMenuScreen::build() {\n    // Empty\n}\n\nvoid MainMenuScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid MainMenuScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    // Get the state handle\n    m_mainMenuSystemViewer = m_soaState->clientState.systemViewer;\n\n    m_soaState->clientState.spaceCamera.init(m_window->getAspectRatio());\n    \n\n    initInput();\n\n    m_soaState->clientState.systemViewer->init(m_window->getViewportDims(),\n                                               &m_soaState->clientState.spaceCamera, m_soaState->spaceSystem, m_inputMapper);\n    m_mainMenuSystemViewer = m_soaState->clientState.systemViewer;\n\n    m_ambLibrary = new AmbienceLibrary;\n    m_ambLibrary->addTrack(\"Menu\", \"Andromeda Fallen\", \"Data/Sound/Music/Andromeda Fallen.ogg\");\n    m_ambLibrary->addTrack(\"Menu\", \"Brethren\", \"Data/Sound/Music/Brethren.mp3\");\n    m_ambLibrary->addTrack(\"Menu\", \"Crystalite\", \"Data/Sound/Music/Crystalite.mp3\");\n    m_ambLibrary->addTrack(\"Menu\", \"Stranded\", \"Data/Sound/Music/Stranded.mp3\");\n    m_ambLibrary->addTrack(\"Menu\", \"Toxic Haze\", \"Data/Sound/Music/Toxic Haze.mp3\");\n    m_ambLibrary->addTrack(\"Menu\", \"BGM Unknown\", \"Data/Sound/Music/BGM Unknown.mp3\");\n    m_ambPlayer = new AmbiencePlayer;\n    m_ambPlayer->init(m_commonState->soundEngine, m_ambLibrary);\n\n    m_spaceSystemUpdater = std::make_unique<SpaceSystemUpdater>();\n    m_spaceSystemUpdater->init(m_soaState);\n\n    // Initialize the user interface\n    m_formFont.init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n    initUI();\n\n    // Init rendering\n    initRenderPipeline();\n\n    // TODO(Ben): Do this or something\n    // Run the update thread for updating the planet\n    //m_updateThread = new std::thread(&MainMenuScreen::updateThreadFunc, this);\n\n    m_ambPlayer->setVolume(soaOptions.get(OPT_MUSIC_VOLUME).value.f);\n    m_ambPlayer->setToTrack(\"Menu\", 3);\n\n    m_isFullscreen = soaOptions.get(OPT_BORDERLESS).value.b;\n    m_isBorderless = soaOptions.get(OPT_FULLSCREEN).value.b;\n}\n\nvoid MainMenuScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    vui::InputDispatcher::window.onResize -= makeDelegate(this, &MainMenuScreen::onWindowResize);\n    vui::InputDispatcher::window.onClose -= makeDelegate(this, &MainMenuScreen::onWindowClose);\n    SoaEngine::optionsController.OptionsChange -= makeDelegate(this, &MainMenuScreen::onOptionsChange);\n    m_renderer.setShowUI(false);\n    m_formFont.dispose();\n    m_ui.dispose();\n\n    m_soaState->clientState.systemViewer->stopInput();\n\n    m_threadRunning = false;\n    //m_updateThread->join();\n    //delete m_updateThread;\n\n    delete m_inputMapper;\n\n    m_ambPlayer->dispose();\n    delete m_ambLibrary;\n    delete m_ambPlayer;\n}\n\nvoid MainMenuScreen::update(const vui::GameTime& gameTime) {\n\n    // Check for UI reload\n    if (m_shouldReloadUI) {\n        reloadUI();\n    }\n\n    if (m_newGameClicked) newGame(\"TEST\");\n\n    if (m_uiEnabled) m_ui.update(gameTime.elapsed);\n\n    { // Handle time warp\n        const f64 TIME_WARP_SPEED = 1000.0 + (f64)m_inputMapper->getInputState(INPUT_SPEED_TIME) * 10000.0;\n        bool isWarping = false;\n        if (m_inputMapper->getInputState(INPUT_TIME_BACK)) {\n            isWarping = true;\n            m_soaState->time -= TIME_WARP_SPEED;\n        }\n        if (m_inputMapper->getInputState(INPUT_TIME_FORWARD)) {\n            isWarping = true;\n            m_soaState->time += TIME_WARP_SPEED;\n        }\n        if (isWarping) {\n            m_soaState->clientState.spaceCamera.setSpeed(1.0);\n        } else {\n            m_soaState->clientState.spaceCamera.setSpeed(0.3);\n        }\n    }\n\n    //m_soaState->time += m_soaState->timeStep;\n    m_spaceSystemUpdater->update(m_soaState, m_soaState->clientState.spaceCamera.getPosition(), f64v3(0.0));\n    m_spaceSystemUpdater->glUpdate(m_soaState);\n    m_mainMenuSystemViewer->update();\n\n    m_ambPlayer->update((f32)gameTime.elapsed);\n    m_commonState->soundEngine->update(vsound::Listener());\n}\n\nvoid MainMenuScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_soaState->clientState.spaceCamera.updateProjection();\n    m_renderer.render();\n}\n\nvoid MainMenuScreen::initInput() {\n    m_inputMapper = new InputMapper;\n    initInputs(m_inputMapper);\n    // Reload space system event\n  \n    m_inputMapper->get(INPUT_RELOAD_SYSTEM).downEvent += makeDelegate(this, &MainMenuScreen::onReloadSystem);\n    m_inputMapper->get(INPUT_RELOAD_SHADERS).downEvent += makeDelegate(this, &MainMenuScreen::onReloadShaders);\n    m_inputMapper->get(INPUT_RELOAD_UI).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 i VORB_MAYBE_UNUSED) { m_shouldReloadUI = true; });\n    m_inputMapper->get(INPUT_TOGGLE_UI).downEvent += makeDelegate(this, &MainMenuScreen::onToggleUI);\n    // TODO(Ben): addFunctor = memory leak\n    m_inputMapper->get(INPUT_TOGGLE_AR).downEvent.addFunctor([&](Sender s VORB_UNUSED, ui32 i VORB_UNUSED) {\n        m_renderer.toggleAR(); });\n    m_inputMapper->get(INPUT_CYCLE_COLOR_FILTER).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 i VORB_MAYBE_UNUSED) {\n        m_renderer.cycleColorFilter(); });\n    m_inputMapper->get(INPUT_SCREENSHOT).downEvent.addFunctor([&](Sender s VORB_MAYBE_UNUSED, ui32 i VORB_MAYBE_UNUSED) {\n        m_renderer.takeScreenshot(); });\n    m_inputMapper->get(INPUT_DRAW_MODE).downEvent += makeDelegate(this, &MainMenuScreen::onToggleWireframe);\n\n    vui::InputDispatcher::window.onResize += makeDelegate(this, &MainMenuScreen::onWindowResize);\n    vui::InputDispatcher::window.onClose += makeDelegate(this, &MainMenuScreen::onWindowClose);\n    SoaEngine::optionsController.OptionsChange += makeDelegate(this, &MainMenuScreen::onOptionsChange);\n\n    m_inputMapper->startInput();\n}\n\nvoid MainMenuScreen::initRenderPipeline() {\n    //m_renderer.init(m_window, m_commonState->loadContext, this);\n}\n\nvoid MainMenuScreen::initUI() {\n    m_ui.init(this, &m_app->getWindow(), nullptr, &m_formFont);\n    m_ui.makeViewFromScript(\"Main Menu\", 1, \"Data/UI/Forms/main_menu.form.lua\");\n}\n\nvoid MainMenuScreen::loadGame(const nString& fileName VORB_UNUSED) {\n    //std::cout << \"Loading Game: \" << fileName << std::endl;\n\n    //initSaveIomanager(fileName);\n\n    //// Check the planet string\n    //nString planetName = fileManager.getWorldString(fileName + \"/World/\");\n    //if (planetName == \"\") {\n    //    std::cout << \"NO PLANET NAME\";\n    //    return;\n    //}\n\n    //m_state = vui::ScreenState::CHANGE_NEXT;\n}\n\nvoid MainMenuScreen::newGame(const nString& fileName) {\n\n    if (!m_mainMenuSystemViewer->getSelectedPlanet()) {\n        m_newGameClicked = false;\n        return;\n    }\n\n    m_soaState->clientState.isNewGame = true;\n    m_soaState->clientState.startSpacePos = m_mainMenuSystemViewer->getClickPos();\n    f64v3 normal = glm::normalize(m_soaState->clientState.startSpacePos);\n    // Don't spawn underwater\n    if (glm::length(m_soaState->clientState.startSpacePos) < m_mainMenuSystemViewer->getTargetRadius()) {\n        m_soaState->clientState.startSpacePos = normal * m_mainMenuSystemViewer->getTargetRadius();\n    }\n    // Push out by 5 voxels\n    m_soaState->clientState.startSpacePos += glm::normalize(m_soaState->clientState.startSpacePos) * 5.0 * KM_PER_VOXEL;\n\n    m_soaState->clientState.startingPlanet = m_mainMenuSystemViewer->getSelectedPlanet();\n    vecs::EntityID startingPlanet = m_soaState->clientState.startingPlanet;\n\n    { // Compute start location\n        SpaceSystem* spaceSystem = m_soaState->spaceSystem;\n        auto& arcmp = spaceSystem->axisRotation.getFromEntity(startingPlanet);\n\n        m_soaState->clientState.startSpacePos = arcmp.currentOrientation * m_soaState->clientState.startSpacePos;\n    }\n\n    std::cout << \"Making new game: \" << fileName << std::endl;\n\n    initSaveIomanager(fileName);  \n\n    m_state = vui::ScreenState::CHANGE_NEXT;\n}\n\nvoid MainMenuScreen::initSaveIomanager(const vio::Path& savePath) {\n\n    vio::IOManager& ioManager = m_soaState->saveFileIom;\n    // Make sure the Saves and savePath directories exist\n    ioManager.setSearchDirectory(\"\");\n    ioManager.makeDirectory(\"Saves\");\n    ioManager.makeDirectory(savePath);\n\n    ioManager.setSearchDirectory(savePath);\n\n    ioManager.makeDirectory(\"players\");\n    ioManager.makeDirectory(\"system\");\n    ioManager.makeDirectory(\"cache\");\n}\n\nvoid MainMenuScreen::reloadUI() {\n    m_ui.dispose();\n    initUI();\n\n    m_shouldReloadUI = false;\n    printf(\"UI was reloaded.\\n\");\n}\n\nvoid MainMenuScreen::onReloadSystem(Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n    SoaEngine::destroySpaceSystem(m_soaState);\n    SoaEngine::loadSpaceSystem(m_soaState, \"StarSystems/Trinity\");\n    CinematicCamera tmp = m_soaState->clientState.spaceCamera; // Store camera so the view doesn't change\n    m_soaState->clientState.systemViewer->init(m_window->getViewportDims(),\n                                               &m_soaState->clientState.spaceCamera, m_soaState->spaceSystem,\n                                   m_inputMapper);\n    m_soaState->clientState.spaceCamera = tmp; // Restore old camera\n    m_renderer.dispose(m_commonState->loadContext);\n    initRenderPipeline();\n}\n\nvoid MainMenuScreen::onReloadShaders(Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n    printf(\"Reloading Shaders...\\n\");\n    m_renderer.dispose(m_commonState->loadContext);\n\n    m_renderer.init(m_commonState->window, m_commonState->loadContext, this, m_commonState);\n    m_renderer.hook();\n    m_commonState->loadContext.begin();\n    m_renderer.load(m_commonState->loadContext);\n\n    \n    while (!m_renderer.isLoaded()) {\n        m_commonState->loadContext.processRequests(1);\n        SDL_Delay(1);\n    }\n\n    m_commonState->loadContext.end();\n\n    printf(\"Done!\\n\");\n}\n\nvoid MainMenuScreen::onQuit(Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n    m_window->saveSettings();\n    SoaEngine::destroyAll(m_soaState);\n    exit(0);\n}\n\nvoid MainMenuScreen::onWindowResize(Sender s VORB_MAYBE_UNUSED, const vui::WindowResizeEvent& e VORB_MAYBE_UNUSED) {\n    SoaEngine::optionsController.setInt(\"Screen Width\", e.w);\n    SoaEngine::optionsController.setInt(\"Screen Height\", e.h);\n    soaOptions.get(OPT_SCREEN_WIDTH).value.i = e.w;\n    soaOptions.get(OPT_SCREEN_HEIGHT).value.i = e.h;\n    if (m_uiEnabled) m_ui.onOptionsChanged();\n    m_soaState->clientState.spaceCamera.setAspectRatio(m_window->getAspectRatio());\n    m_mainMenuSystemViewer->setViewport(ui32v2(e.w, e.h));\n}\n\nvoid MainMenuScreen::onWindowClose(Sender s VORB_MAYBE_UNUSED) {\n    onQuit(s, 0);\n}\n\nvoid MainMenuScreen::onOptionsChange(Sender s VORB_MAYBE_UNUSED) {\n    bool fullscreen = soaOptions.get(OPT_FULLSCREEN).value.b;\n    bool borderless = soaOptions.get(OPT_BORDERLESS).value.b;\n    bool screenChanged = false;\n    ui32v2 screenSize = m_window->getViewportDims();\n    if (screenSize.x != (ui32)soaOptions.get(OPT_SCREEN_WIDTH).value.i ||\n        screenSize.y != (ui32)soaOptions.get(OPT_SCREEN_HEIGHT).value.i) {\n        m_window->setScreenSize(soaOptions.get(OPT_SCREEN_WIDTH).value.i, soaOptions.get(OPT_SCREEN_HEIGHT).value.i);\n        screenChanged = true;\n    }\n    m_window->setFullscreen(fullscreen);\n    m_window->setBorderless(borderless);\n\n    if (soaOptions.get(OPT_VSYNC).value.b) {\n        m_window->setSwapInterval(vui::GameSwapInterval::V_SYNC);\n    } else {\n        m_window->setSwapInterval(vui::GameSwapInterval::UNLIMITED_FPS);\n    }\n    TerrainPatch::setQuality(soaOptions.get(OPT_PLANET_DETAIL).value.i);\n    m_ambPlayer->setVolume(soaOptions.get(OPT_MUSIC_VOLUME).value.f);\n\n    // Re-center the window\n    if (screenChanged || m_isFullscreen != fullscreen || m_isBorderless != borderless) {\n        m_isFullscreen = fullscreen;\n        m_isBorderless = borderless;\n        m_window->setPosition(SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);\n    }\n}\n\nvoid MainMenuScreen::onToggleUI(Sender s VORB_MAYBE_UNUSED, ui32 i VORB_MAYBE_UNUSED) {\n    m_renderer.toggleUI();\n    m_uiEnabled = !m_uiEnabled;\n    if (m_uiEnabled) {\n        initUI();\n    } else {\n        m_ui.dispose();\n    }\n}\n\nvoid MainMenuScreen::onToggleWireframe(Sender s VORB_MAYBE_UNUSED, ui32 i VORB_MAYBE_UNUSED) {\n    m_renderer.toggleWireframe();\n}"
  },
  {
    "path": "SoA/MainMenuScreen.h",
    "content": "// \n//  MainMenuScreen.h\n//  Seed Of Andromeda\n//\n//  Created by Ben Arnold on 17 Oct 2014\n//  Copyright 2014 Regrowth Studios\n//  MIT License\n//  \n//  This file provides the main menu screen\n//  implementation. This screen encompasses the\n//  gamestate for the main menu, as well as interaction\n//  with the user interface.\n//\n\n#pragma once\n\n#ifndef MAINMENUSCREEN_H_\n#define MAINMENUSCREEN_H_\n\n#include <Vorb/Random.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/ui/IGameScreen.h>\n\n#include \"LoadMonitor.h\"\n#include \"MainMenuRenderer.h\"\n#include \"MainMenuScriptedUI.h\"\n#include \"Camera.h\"\n#include \"SpaceSystemUpdater.h\"\n\nclass App;\n\nclass InputMapper;\nclass MainMenuLoadScreen;\nclass MainMenuSystemViewer;\nstruct CommonState;\nstruct SoaState;\n\nDECL_VSOUND(class Engine)\nDECL_VUI(struct WindowResizeEvent);\nclass AmbienceLibrary;\nclass AmbiencePlayer;\n\nclass MainMenuScreen : public vui::IAppScreen<App> {\n    friend class MainMenuScriptedUI;\n    friend class MainMenuRenderer;\n    friend class MainMenuLoadScreen; // So it can load our assets\n    friend class GameplayLoadScreen; // So it can use our renderer\npublic:\n    MainMenuScreen(const App* app, CommonState* state);\n    ~MainMenuScreen();\n\n    virtual i32 getNextScreen() const;\n    virtual i32 getPreviousScreen() const;\n\n    virtual void build();\n    virtual void destroy(const vui::GameTime& gameTime);\n\n    virtual void onEntry(const vui::GameTime& gameTime);\n    virtual void onExit(const vui::GameTime& gameTime);\n\n    virtual void update(const vui::GameTime& gameTime);\n    virtual void draw(const vui::GameTime& gameTime);\n\n    // Getters\n    SoaState* getSoAState() const { return m_soaState; }\nprivate:\n\n    /// Initializes event delegates and InputManager\n    void initInput();\n\n    /// Initializes the rendering\n    void initRenderPipeline();\n\n    /// Initializes user interface\n    void initUI();\n\n    /// Loads a save file and prepares to play the game\n    /// @param fileName: The name of the save file\n    void loadGame(const nString& fileName);\n\n    /// Makes a new save file and prepares to play the game\n    /// @param fileName: The name of the save file\n    void newGame(const nString& fileName);\n\n    /// Sets up iomanager and makes save file directories if they don't exist\n    void initSaveIomanager(const vio::Path& savePath);\n\n    /// Reloads the user interface\n    void reloadUI();\n\n    /// Cycles the draw mode for wireframe\n    void cycleDrawMode();\n\n    // --------------- Event handlers ---------------\n    void onReloadSystem(Sender s, ui32 a);\n    void onReloadShaders(Sender s, ui32 a);\n    void onQuit(Sender s, ui32 a);\n    void onWindowResize(Sender s, const vui::WindowResizeEvent& e);\n    void onWindowClose(Sender s);\n    void onOptionsChange(Sender s);\n    void onToggleUI(Sender s, ui32 i);\n    void onToggleWireframe(Sender s, ui32 i);\n    // ----------------------------------------------\n\n    CommonState* m_commonState = nullptr;\n    SoaState* m_soaState = nullptr;\n\n    vio::IOManager m_ioManager; ///< Helper class for IO operations\n\n    InputMapper* m_inputMapper = nullptr;\n\n    std::unique_ptr<SpaceSystemUpdater> m_spaceSystemUpdater = nullptr;\n\n    std::thread* m_updateThread = nullptr; ///< The thread that updates the planet. Runs updateThreadFunc()\n    volatile bool m_threadRunning; ///< True when the thread should be running\n\n    MainMenuRenderer m_renderer; ///< This handles all rendering for the main menu\n    MainMenuScriptedUI m_ui; ///< The UI form\n    vg::SpriteFont m_formFont; ///< The UI font\n\n    MainMenuSystemViewer* m_mainMenuSystemViewer = nullptr;\n\n    AmbienceLibrary* m_ambLibrary = nullptr;\n    AmbiencePlayer* m_ambPlayer = nullptr;\n    vui::GameWindow* m_window = nullptr;\n    bool m_uiEnabled = true;\n\n    bool m_isFullscreen = false;\n    bool m_isBorderless = false;\n\n    bool m_newGameClicked = false;\n    bool m_shouldReloadUI = false;\n};\n\n#endif // MAINMENUSCREEN_H_\n"
  },
  {
    "path": "SoA/MainMenuScriptedUI.cpp",
    "content": "#include \"stdafx.h\"\n#include \"MainMenuScriptedUI.h\"\n#include \"SoaEngine.h\"\n#include \"SoAState.h\"\n#include \"MainMenuScreen.h\"\n#include \"MainMenuSystemViewer.h\"\n\n#include <Vorb/ui/script/ViewScriptEnvironment.h>\n#include <Vorb/script/lua/Environment.h>\n#include <Vorb/Event.hpp>\n#include <Vorb/ui/KeyStrings.h>\n\n#define ON_TARGET_CHANGE_NAME \"onTargetChange\"\n\nMainMenuScriptedUI::MainMenuScriptedUI() {\n    // Empty\n}\n\nMainMenuScriptedUI::~MainMenuScriptedUI() {\n    // Empty\n}\n\nvoid MainMenuScriptedUI::init(vui::IGameScreen* ownerScreen, const vui::GameWindow* window, vg::TextureCache* textureCache, vg::SpriteFont* defaultFont /*= nullptr*/, vg::SpriteBatch* spriteBatch /*= nullptr*/) {\n    MainMenuScreen* mainMenuScreen = ((MainMenuScreen*)ownerScreen);\n    m_inputMapper = mainMenuScreen->m_inputMapper;\n\n    mainMenuScreen->m_mainMenuSystemViewer->TargetChange += makeDelegate(this, &MainMenuScriptedUI::onTargetChange);\n\n    ScriptedUI::init(ownerScreen, window, textureCache, defaultFont, spriteBatch); \n}\n\nvoid MainMenuScriptedUI::prepareScriptEnv(ViewEnv* viewEnv) {\n    vui::ScriptedUI<vscript::lua::Environment>::prepareScriptEnv(viewEnv);\n    vscript::lua::Environment* env = static_cast<vscript::lua::Environment*>(viewEnv->getEnv());\n\n    SoaEngine::optionsController.registerScripting<vscript::lua::Environment>(env);\n\n    // Controls menu stuff\n    env->setNamespaces(\"Controls\");\n    env->addCDelegate(\"size\",                makeDelegate(this, &MainMenuScriptedUI::getNumInputs));\n    env->addCDelegate(\"getInput\",            makeDelegate(this, &MainMenuScriptedUI::getInput));\n    env->addCDelegate(\"getKey\",              makeDelegate(this, &MainMenuScriptedUI::getKey));\n    env->addCDelegate(\"getDefaultKey\",       makeDelegate(this, &MainMenuScriptedUI::getDefaultKey));\n    env->addCDelegate(\"getKeyString\",        makeDelegate(this, &MainMenuScriptedUI::getKeyString));\n    env->addCDelegate(\"getDefaultKeyString\", makeDelegate(this, &MainMenuScriptedUI::getDefaultKeyString));\n    env->addCDelegate(\"getName\",             makeDelegate(this, &MainMenuScriptedUI::getName));\n\n    env->setNamespaces();\n    env->addCDelegate(\"newGame\", makeDelegate(this, &MainMenuScriptedUI::newGame));\n\n    env->setNamespaces(\"Game\");\n    env->addCDelegate(\"exit\", makeDelegate(this, &MainMenuScriptedUI::onExit));\n\n    // TODO(Ben): Expose and use ECS instead???\n    env->setNamespaces(\"Space\");\n    env->addCDelegate(\"getTargetBody\",       makeDelegate(this, &MainMenuScriptedUI::getTargetBody));\n    env->addCDelegate(\"getBodyName\",         makeDelegate(this, &MainMenuScriptedUI::getBodyName));\n    env->addCDelegate(\"getBodyParentName\",   makeDelegate(this, &MainMenuScriptedUI::getBodyName));\n    env->addCDelegate(\"getBodyTypeName\",     makeDelegate(this, &MainMenuScriptedUI::getBodyTypeName));\n    env->addCDelegate(\"getBodyMass\",         makeDelegate(this, &MainMenuScriptedUI::getBodyMass));\n    env->addCDelegate(\"getBodyDiameter\",     makeDelegate(this, &MainMenuScriptedUI::getBodyDiameter));\n    env->addCDelegate(\"getBodyRotPeriod\",    makeDelegate(this, &MainMenuScriptedUI::getBodyRotPeriod));\n    env->addCDelegate(\"getBodyOrbPeriod\",    makeDelegate(this, &MainMenuScriptedUI::getBodyOrbPeriod));\n    env->addCDelegate(\"getBodyAxialTilt\",    makeDelegate(this, &MainMenuScriptedUI::getBodyAxialTilt));\n    env->addCDelegate(\"getBodyEccentricity\", makeDelegate(this, &MainMenuScriptedUI::getBodyEccentricity));\n    env->addCDelegate(\"getBodyInclination\",  makeDelegate(this, &MainMenuScriptedUI::getBodyInclination));\n    env->addCDelegate(\"getBodySemiMajor\",    makeDelegate(this, &MainMenuScriptedUI::getBodySemiMajor));\n    env->addCDelegate(\"getGravityAccel\",     makeDelegate(this, &MainMenuScriptedUI::getGravityAccel));\n    env->addCDelegate(\"getVolume\",           makeDelegate(this, &MainMenuScriptedUI::getVolume));\n    env->addCDelegate(\"getAverageDensity\",   makeDelegate(this, &MainMenuScriptedUI::getAverageDensity));\n    env->setNamespaces();\n}\n\nsize_t MainMenuScriptedUI::getNumInputs() {\n    return m_inputMapper->getInputLookup().size();\n}\n\nInputMapper::InputID MainMenuScriptedUI::getInput(int index) {\n    // This is slow, but that is ok.\n    auto it = m_inputMapper->getInputLookup().begin();\n    std::advance(it, index);\n    return it->second;\n}\n\nVirtualKey MainMenuScriptedUI::getKey(InputMapper::InputID id) {\n    return m_inputMapper->getKey(id);\n}\n\nVirtualKey MainMenuScriptedUI::getDefaultKey(InputMapper::InputID id) {\n    return m_inputMapper->get(id).defaultKey;\n}\n\nnString MainMenuScriptedUI::getKeyString(InputMapper::InputID id) {\n    return nString(VirtualKeyStrings[m_inputMapper->getKey(id)]);\n}\n\nnString MainMenuScriptedUI::getDefaultKeyString(InputMapper::InputID id) {\n    return nString(VirtualKeyStrings[m_inputMapper->get(id).defaultKey]);\n}\n\nnString MainMenuScriptedUI::getName(InputMapper::InputID id) {\n    return m_inputMapper->get(id).name;\n}\n\nvoid MainMenuScriptedUI::onExit(int code) {\n    ((MainMenuScreen*)m_ownerScreen)->onQuit(this, code);\n}\n\nvoid MainMenuScriptedUI::onTargetChange(Sender, vecs::EntityID id) {\n    // TODO(Ben): Race condition???\n    for (auto& view : m_views) {\n        if (view.second.viewport->isEnabled()) {\n            vscript::IEnvironment<vscript::lua::Environment>* env = view.second.viewEnv->getEnv();\n            Delegate<void, vecs::EntityID> del = env->template getScriptDelegate<void, vecs::EntityID>(ON_TARGET_CHANGE_NAME);\n            if (del != NilDelegate<void, vecs::EntityID>) del(id);\n        }\n    }\n}\n\nvoid MainMenuScriptedUI::newGame() {\n    ((MainMenuScreen*)m_ownerScreen)->m_newGameClicked = true;\n}\n\nvecs::EntityID MainMenuScriptedUI::getTargetBody() {\n    return ((MainMenuScreen*)m_ownerScreen)->m_mainMenuSystemViewer->getTargetBody();\n}\n\nnString MainMenuScriptedUI::getBodyName(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return state->spaceSystem->namePosition.getFromEntity(entity).name;\n}\n\nnString MainMenuScriptedUI::getBodyParentName(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    auto parentOID = state->spaceSystem->orbit.getFromEntity(entity).parentOrbId;\n    if (parentOID == 0) return \"None\";\n    auto parentNpID = state->spaceSystem->orbit.get(parentOID).npID;\n    return state->spaceSystem->namePosition.get(parentNpID).name;\n}\n\nnString MainMenuScriptedUI::getBodyTypeName(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    auto t = state->spaceSystem->orbit.getFromEntity(entity).type;\n    nString n;\n    switch (t) {\n        case SpaceObjectType::BARYCENTER:\n            n = \"Barycenter\"; break;\n        case SpaceObjectType::STAR: // TODO(Ben): Spectral classes\n            n = \"Star\"; break;\n        case SpaceObjectType::PLANET:\n            n = \"Planet\"; break;\n        case SpaceObjectType::DWARF_PLANET:\n            n = \"Dwarf Planet\"; break;\n        case SpaceObjectType::MOON:\n            n = \"Moon\"; break;\n        case SpaceObjectType::DWARF_MOON:\n            n = \"Dwarf Moon\"; break;\n        case SpaceObjectType::ASTEROID:\n            n = \"Asteroid\"; break;\n        case SpaceObjectType::COMET:\n            n = \"Comet\"; break;\n        default:\n            n = \"UNKNOWN\"; break;\n    }\n    return n;\n}\n\nf32 MainMenuScriptedUI::getBodyMass(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return (f32)state->spaceSystem->sphericalGravity.getFromEntity(entity).mass;\n}\n\nf32 MainMenuScriptedUI::getBodyDiameter(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return (f32)state->spaceSystem->sphericalGravity.getFromEntity(entity).radius * 2.0f;\n}\n\nf32 MainMenuScriptedUI::getBodyRotPeriod(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return (f32)state->spaceSystem->axisRotation.getFromEntity(entity).period;\n}\n\nf32 MainMenuScriptedUI::getBodyOrbPeriod(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return (f32)state->spaceSystem->orbit.getFromEntity(entity).t;\n}\n\nf32 MainMenuScriptedUI::getBodyAxialTilt(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return (f32)state->spaceSystem->axisRotation.getFromEntity(entity).tilt;\n}\n\nf32 MainMenuScriptedUI::getBodyEccentricity(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return (f32)state->spaceSystem->orbit.getFromEntity(entity).e;\n}\n\nf32 MainMenuScriptedUI::getBodyInclination(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return (f32)state->spaceSystem->orbit.getFromEntity(entity).i;\n}\n\nf32 MainMenuScriptedUI::getBodySemiMajor(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    return (f32)state->spaceSystem->orbit.getFromEntity(entity).a;\n}\n\nf32 MainMenuScriptedUI::getGravityAccel(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    auto& sgCmp = state->spaceSystem->sphericalGravity.getFromEntity(entity);\n    f32 rad = (f32)(sgCmp.radius * M_PER_KM);\n    return (f32)(M_G * sgCmp.mass / (rad * rad));\n}\n\nf32 MainMenuScriptedUI::getVolume(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    // TODO(Ben): Handle oblateness\n    auto& sgCmp = state->spaceSystem->sphericalGravity.getFromEntity(entity);\n    f32 rad = (f32)(sgCmp.radius * M_PER_KM);\n    return (f32)(4.0 / 3.0 * M_PI * rad * rad * rad);\n}\n\nf32 MainMenuScriptedUI::getAverageDensity(vecs::EntityID entity) {\n    SoaState* state = ((MainMenuScreen*)m_ownerScreen)->m_soaState;\n    // TODO(Ben): This is a double lookup\n    f32 volume = getVolume(entity);\n    return (f32)(state->spaceSystem->sphericalGravity.getFromEntity(entity).mass / volume);\n}\n"
  },
  {
    "path": "SoA/MainMenuScriptedUI.h",
    "content": "///\n/// MainMenuScriptedUI.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 13 May 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Custom main menu UI\n///\n\n#pragma once\n\n#ifndef MainMenuScriptedUI_h__\n#define MainMenuScriptedUI_h__\n\n#include <Vorb/ecs/Entity.h>\n#include <Vorb/script/lua/Environment.h>\n#include <Vorb/ui/ScriptedUI.h>\n#include \"InputMapper.h\"\n\nclass MainMenuScreen;\n\nclass MainMenuScriptedUI : public vui::ScriptedUI<vscript::lua::Environment> {\npublic:\n    MainMenuScriptedUI();\n    ~MainMenuScriptedUI();\n\n    virtual void init(vui::IGameScreen* ownerScreen, const vui::GameWindow* window,\n                        vg::TextureCache* textureCache, vg::SpriteFont* defaultFont = nullptr,\n                            vg::SpriteBatch* spriteBatch = nullptr) override;\n\nprotected:\n    virtual void prepareScriptEnv(ViewEnv* env) override;\n\n    // LUA funcs for controls\n                  size_t getNumInputs();\n    InputMapper::InputID getInput(int index);\n              VirtualKey getKey(InputMapper::InputID id);\n              VirtualKey getDefaultKey(InputMapper::InputID id);\n                 nString getKeyString(InputMapper::InputID id);\n                 nString getDefaultKeyString(InputMapper::InputID id);\n                 nString getName(InputMapper::InputID id);\n                    void onExit(int code);\n                    void onTargetChange(Sender s, vecs::EntityID id);\n                    void newGame();\n\n    // Planet functions (temporary???)\n    vecs::EntityID getTargetBody();\n           nString getBodyName(vecs::EntityID entity);\n           nString getBodyParentName(vecs::EntityID entity);\n           nString getBodyTypeName(vecs::EntityID entity);\n               f32 getBodyMass(vecs::EntityID entity);\n               f32 getBodyDiameter(vecs::EntityID entity);\n               f32 getBodyRotPeriod(vecs::EntityID entity);\n               f32 getBodyOrbPeriod(vecs::EntityID entity);\n               f32 getBodyAxialTilt(vecs::EntityID entity);\n               f32 getBodyEccentricity(vecs::EntityID entity);\n               f32 getBodyInclination(vecs::EntityID entity);\n               f32 getBodySemiMajor(vecs::EntityID entity);\n               f32 getGravityAccel(vecs::EntityID entity);\n               f32 getVolume(vecs::EntityID entity);\n               f32 getAverageDensity(vecs::EntityID entity);\n\n    InputMapper* m_inputMapper = nullptr;\n};\n\n#endif // MainMenuScriptedUI_h__\n"
  },
  {
    "path": "SoA/MainMenuSystemViewer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"MainMenuSystemViewer.h\"\n\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/utils.h>\n\n#include \"Camera.h\"\n#include \"SpaceSystem.h\"\n#include \"TerrainPatch.h\"\n#include \"SphericalHeightmapGenerator.h\"\n\nconst f32 MainMenuSystemViewer::MIN_SELECTOR_SIZE = 12.0f;\nconst f32 MainMenuSystemViewer::MAX_SELECTOR_SIZE = 160.0f;\n\nvoid MainMenuSystemViewer::init(ui32v2 viewport, CinematicCamera* camera,\n                                SpaceSystem* spaceSystem, InputMapper* inputManager) {  \n    m_viewport = viewport;\n    m_camera = camera;\n    m_spaceSystem = spaceSystem;\n    m_inputManager = inputManager;\n\n    mouseButtons[0] = false;\n    mouseButtons[1] = false;\n\n    // Initialize the camera\n    m_camera->setPosition(f64v3(0.0, 200000.0, 0.0));\n\n    // Initialize the camera\n    m_camera->setClippingPlane(10000.0f, 30000000000000.0f);\n    m_camera->setTarget(f64v3(0.0, 0.0, 0.0), f32v3(1.0f, 0.0f, 0.0f), f32v3(0.0f, 0.0f, 1.0f), 20000.0);\n\n    targetBody(\"Aldrin\");\n    // Force target focal point\n    m_camera->setFocalPoint(getTargetPosition() -\n                            f64v3(glm::normalize(m_camera->getDirection())) * getTargetRadius());\n\n    // Register events\n    startInput();\n}\n\nvoid MainMenuSystemViewer::dispose() {\n    stopInput();\n}\n\nvoid MainMenuSystemViewer::update() {\n\n    const f32 HOVER_SPEED = 0.08f;\n    const f32 HOVER_SIZE_INC = 7.0f;\n\n    m_camera->setClippingPlane((f32)(0.1 * KM_PER_M), m_camera->getFarClip());\n    // Target closest point on sphere\n    m_camera->setTargetFocalPoint(getTargetPosition() -\n                                  f64v3(glm::normalize(m_camera->getDirection())) * getTargetRadius());\n\n    m_camera->update();\n\n    for (auto& it : m_spaceSystem->namePosition) {\n        vecs::ComponentID componentID;\n\n        f64v3 relativePos = it.second.position - m_camera->getPosition();\n        f64 distance = glm::length(relativePos);\n        f64 radiusPixels;\n        f64 radius;\n\n        BodyArData& data = bodyArData[it.first];\n        f32 hoverTime = data.hoverTime;\n\n        if (m_camera->pointInFrustum(f32v3(relativePos))) {\n            data.inFrustum = true;\n            // Get screen position \n            f32v3 screenCoords = m_camera->worldToScreenPoint(relativePos);\n            f32v2 xyScreenCoords(screenCoords.x * m_viewport.x, screenCoords.y * m_viewport.y);\n\n            // Get a smooth interpolator with hermite\n            f32 interpolator = hermite(hoverTime);\n\n            // See if it has a radius\n            componentID = m_spaceSystem->sphericalGravity.getComponentID(it.first);\n            if (componentID) {\n                // Get radius of projected sphere\n                radius = m_spaceSystem->sphericalGravity.get(componentID).radius;\n                radiusPixels = (radius /\n                                (tan((f64)m_camera->getFieldOfView() / 2.0) * distance)) *\n                                ((f64)m_viewport.y / 2.0);\n            } else {\n                radius = 1000.0;\n                radiusPixels = (radius /\n                                (tan((f64)m_camera->getFieldOfView() / 2.0) * distance)) *\n                                ((f64)m_viewport.y / 2.0);\n            }\n\n            f32 selectorSize = (f32)(radiusPixels * 2.0 + 3.0);\n            if (selectorSize < MIN_SELECTOR_SIZE) selectorSize = MIN_SELECTOR_SIZE;\n\n            // Interpolate size\n            selectorSize += interpolator * HOVER_SIZE_INC;\n\n            // Detect mouse hover\n            if (glm::length(m_mouseCoords - xyScreenCoords) <= selectorSize / 2.0f) {\n                data.isHovering = true;\n                data.hoverEntity = it.first;\n                hoverTime += HOVER_SPEED;\n                if (hoverTime > 1.0f) hoverTime = 1.0f;\n            } else {\n                data.isHovering = false;\n                hoverTime -= HOVER_SPEED;\n                if (hoverTime < 0.0f) hoverTime = 0.0f;\n            }\n\n            data.hoverTime = hoverTime;\n            data.selectorSize = selectorSize;\n        } else {\n            data.isHovering = false;\n            data.inFrustum = false;\n        }\n    }\n}\n\nvoid MainMenuSystemViewer::startInput() {\n    stopInput();\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [=](Sender s, const vui::MouseButtonEvent& e) { onMouseButtonDown(s, e); });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonUp, [=](Sender s, const vui::MouseButtonEvent& e) { onMouseButtonUp(s, e); });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onMotion, [=](Sender s, const vui::MouseMotionEvent& e) { onMouseMotion(s, e); });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onWheel, [=](Sender s, const vui::MouseWheelEvent& e) { onMouseWheel(s, e); });\n}\n\nvoid MainMenuSystemViewer::stopInput() {\n    m_hooks.dispose();\n}\n\nvoid MainMenuSystemViewer::targetBody(const nString& name) {\n    for (auto& it : m_spaceSystem->namePosition) {\n        if (it.second.name == name) {\n            targetBody(it.first);\n            return;\n        }\n    }\n}\n\nvoid MainMenuSystemViewer::targetBody(vecs::EntityID eid) {\n    if (m_targetEntity != eid) {\n        TargetChange(eid);\n        m_targetEntity = eid;\n        m_targetComponent = m_spaceSystem->namePosition.getComponentID(m_targetEntity);\n    }\n}\n\nf64v3 MainMenuSystemViewer::getTargetPosition() {\n    return m_spaceSystem->namePosition.get(m_targetComponent).position;\n}\n\nf64 MainMenuSystemViewer::getTargetRadius() {\n    return m_spaceSystem->sphericalGravity.getFromEntity(m_targetEntity).radius;\n}\n\nnString MainMenuSystemViewer::getTargetName() {\n    return m_spaceSystem->namePosition.get(m_targetComponent).name;\n}\n\nvoid MainMenuSystemViewer::onMouseButtonDown(Sender sender VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n    m_mouseCoords.x = (f32)e.x;\n    m_mouseCoords.y = (f32)e.y;\n    if (e.button == vui::MouseButton::LEFT) {\n        mouseButtons[0] = true;\n        // Target a body if we clicked on one\n        f64 closestDist = 99999999999999999999999999999.0;\n        vecs::EntityID closestEntity = 0;\n        for (auto& it : bodyArData) {\n            if (it.second.isHovering) {\n\n                // Check distance so we pick only the closest one\n                f64v3 pos = m_spaceSystem->namePosition.getFromEntity(it.first).position;\n                f64 dist = glm::length(pos - m_camera->getPosition());\n                if (dist < closestDist) {\n                    closestDist = dist;\n                    closestEntity = it.first;\n                } else {\n                    it.second.isLandSelected = false;\n                }\n            }\n        }\n\n        // If we selected an entity, then do the target picking\n        if (closestEntity) {\n            targetBody(closestEntity);\n            pickStartLocation(closestEntity);\n        }\n    } else {\n        mouseButtons[1] = true;\n    }\n}\n\nvoid MainMenuSystemViewer::onMouseButtonUp(Sender sender VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n    m_mouseCoords.x = (f32)e.x;\n    m_mouseCoords.y = (f32)e.y;\n    if (e.button == vui::MouseButton::LEFT) {\n        mouseButtons[0] = false;\n    } else {\n        mouseButtons[1] = false;\n    }\n}\n\nvoid MainMenuSystemViewer::onMouseWheel(Sender sender VORB_MAYBE_UNUSED, const vui::MouseWheelEvent& e) {\n#define SCROLL_SPEED 0.1f\n    m_camera->offsetTargetFocalLength((f32)m_camera->getTargetFocalLength() * SCROLL_SPEED * -e.dy);\n    if (m_camera->getTargetFocalLength() < 0.1f) {\n        m_camera->setTargetFocalLength(0.1f);\n    }\n}\n\nvoid MainMenuSystemViewer::onMouseMotion(Sender sender VORB_MAYBE_UNUSED, const vui::MouseMotionEvent& e) {\n    m_mouseCoords.x = (f32)e.x;\n    m_mouseCoords.y = (f32)e.y;\n\n#define MOUSE_SPEED 0.001f\n    if (mouseButtons[0]) {\n        m_camera->rotateFromMouse((f32)-e.dx, (f32)-e.dy, MOUSE_SPEED);\n    }\n    if (mouseButtons[1]) {\n        m_camera->rollFromMouse((f32)e.dx, MOUSE_SPEED);\n    }\n}\n\nvoid MainMenuSystemViewer::pickStartLocation(vecs::EntityID eid) {\n    // Check to see if it even has terrain by checking if it has a generator\n    if (!m_spaceSystem->sphericalTerrain.getFromEntity(m_targetEntity).cpuGenerator) return;\n    // Select the planet\n    m_selectedPlanet = eid;\n\n    f32v2 ndc = f32v2((m_mouseCoords.x / m_viewport.x) * 2.0f - 1.0f,\n        1.0f - (m_mouseCoords.y / m_viewport.y) * 2.0f);\n    f64v3 pickRay(m_camera->getPickRay(ndc));\n\n    vecs::ComponentID cid = m_spaceSystem->namePosition.getComponentID(eid);\n    if (!cid) return;\n    f64v3 centerPos = m_spaceSystem->namePosition.get(cid).position;\n    f64v3 pos = f64v3(centerPos - m_camera->getPosition());\n\n    cid = m_spaceSystem->sphericalGravity.getComponentID(eid);\n    if (!cid) return;\n    f64 radius = m_spaceSystem->sphericalGravity.get(cid).radius;\n\n    // Compute the intersection\n    f64v3 normal, hitpoint;\n    f64 distance;\n    if (IntersectionUtils::sphereIntersect(pickRay, f64v3(0.0f), pos, radius, hitpoint, distance, normal)) {\n        hitpoint -= pos;\n        cid = m_spaceSystem->axisRotation.getComponentID(eid);\n        if (cid) {\n            f64q rot = m_spaceSystem->axisRotation.get(cid).currentOrientation;\n            hitpoint = glm::inverse(rot) * hitpoint;\n        }\n\n        // Compute face and grid position\n        PlanetHeightData heightData;\n        m_spaceSystem->sphericalTerrain.getFromEntity(m_targetEntity).cpuGenerator->generateHeightData(heightData, glm::normalize(hitpoint));\n        f64 height = heightData.height * KM_PER_VOXEL;\n\n        m_clickPos = f64v3(hitpoint + glm::normalize(hitpoint) * height);\n\n        auto& data = bodyArData[eid];\n        data.selectedPos = hitpoint;\n        data.isLandSelected = true;\n    }\n}\n"
  },
  {
    "path": "SoA/MainMenuSystemViewer.h",
    "content": "///\n/// MainMenuSystemViewer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 3 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Controls the camera and state when viewing/selecting\n/// the star system in the main menu.\n///\n\n#pragma once\n\n#ifndef MainMenuSystemViewer_h__\n#define MainMenuSystemViewer_h__\n\n#include <Vorb/Vorb.h>\n// Temporary\n#include <Vorb/ui/MouseInputDispatcher.h>\n#include <Vorb/ecs/ECS.h>\n\n#include \"VoxelCoordinateSpaces.h\"\n\nclass CinematicCamera;\nclass InputMapper;\nclass SpaceSystem;\n\nclass MainMenuSystemViewer {\npublic:\n\n    void init(ui32v2 viewport, CinematicCamera* camera, SpaceSystem* spaceSystem, InputMapper* inputManager);\n\n    void dispose();\n\n    void setViewport(const ui32v2& viewPort) { m_viewport = viewPort; }\n\n    void update();\n\n    void startInput();\n\n    void stopInput();\n\n    struct BodyArData {\n        f32 hoverTime = 0.0f;\n        f32 selectorSize = 0.0f;\n        bool inFrustum = false;\n        vecs::EntityID hoverEntity = 0;\n        bool isHovering = false;\n        bool isLandSelected = false;\n        f32v3 selectedPos;\n    };\n    const BodyArData* finBodyAr(vecs::EntityID eid) const {\n        auto it = bodyArData.find(eid);\n        if (it == bodyArData.end()) return nullptr;\n        return &it->second;\n    }\n\n    /// Targets a named body\n    /// @param name: Name of the body\n    void targetBody(const nString& name);\n    /// Targets an entity\n    /// @param eid: Entity ID\n    void targetBody(vecs::EntityID eid);\n\n    /// Getters\n    vecs::EntityID getSelectedPlanet() const { return m_selectedPlanet; }\n    vecs::EntityID getTargetBody() const { return m_targetEntity; }\n    const f64v3& getClickPos() const { return m_clickPos; }\n\n    /// Gets the position of the targeted entity\n    /// @return position\n    f64v3 getTargetPosition();\n\n    /// Gets the position of the targeted entity\n    /// @return radius\n    f64 getTargetRadius();\n\n    /// Gets the name of the targeted component\n    /// @return position\n    nString getTargetName();\n\n    static const f32 MIN_SELECTOR_SIZE;\n    static const f32 MAX_SELECTOR_SIZE;\n\n    Event<vecs::EntityID> TargetChange;\n\nprivate:\n    // Events\n    AutoDelegatePool m_hooks; ///< Input hooks reservoir\n    void onMouseButtonDown(Sender sender, const vui::MouseButtonEvent& e);\n    void onMouseButtonUp(Sender sender, const vui::MouseButtonEvent& e);\n    void onMouseWheel(Sender sender, const vui::MouseWheelEvent& e);\n    void onMouseMotion(Sender sender, const vui::MouseMotionEvent& e);\n\n    void pickStartLocation(vecs::EntityID eid);\n\n    nString currentBody = \"\";\n\n    std::map <vecs::EntityID, BodyArData> bodyArData;\n\n    vecs::EntityID m_targetEntity = 1; ///< Current entity we are focusing on\n    vecs::ComponentID m_targetComponent = 1; ///< namePositionComponent of the targetEntity\n\n    bool mouseButtons[2];\n    f32v2 m_mouseCoords = f32v2(-1.0f);\n    f32v2 m_viewport;\n    f64v3 m_clickPos = f64v3(0.0);\n\n    vecs::EntityID m_selectedPlanet = 0;\n\n    CinematicCamera* m_camera = nullptr;\n    SpaceSystem* m_spaceSystem = nullptr;\n    InputMapper* m_inputManager = nullptr;\n};\n\n#endif // MainMenuSystemViewer_h__"
  },
  {
    "path": "SoA/MarchingCubesTable.h",
    "content": "///\n/// MarchingCubesTable.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 14 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Tables for marching cubes algorithm\n///\n\n#pragma once\n\n#ifndef MarchingCubesTable_h__\n#define MarchingCubesTable_h__\n\n\n// Tables used by Marching Cubes Algorithm\n// these tables came from Paul Baurke's web page at \n// http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/\n\nstatic int edgeTable[256] = {\n    0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,\n    0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,\n    0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,\n    0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,\n    0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,\n    0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,\n    0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,\n    0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,\n    0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,\n    0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,\n    0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,\n    0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,\n    0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,\n    0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,\n    0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,\n    0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,\n    0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,\n    0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,\n    0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,\n    0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,\n    0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,\n    0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,\n    0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,\n    0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,\n    0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,\n    0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,\n    0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,\n    0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,\n    0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,\n    0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,\n    0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,\n    0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };\n\nstatic int triTable[256][16] =\n{ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 },\n{ 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 },\n{ 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 },\n{ 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 },\n{ 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 },\n{ 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 },\n{ 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 },\n{ 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 },\n{ 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 },\n{ 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 },\n{ 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 },\n{ 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 },\n{ 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 },\n{ 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 },\n{ 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 },\n{ 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 },\n{ 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 },\n{ 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 },\n{ 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 },\n{ 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 },\n{ 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 },\n{ 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 },\n{ 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 },\n{ 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 },\n{ 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 },\n{ 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 },\n{ 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 },\n{ 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 },\n{ 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 },\n{ 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 },\n{ 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 },\n{ 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 },\n{ 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 },\n{ 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 },\n{ 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 },\n{ 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 },\n{ 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 },\n{ 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 },\n{ 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },\n{ 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 },\n{ 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 },\n{ 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 },\n{ 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 },\n{ 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 },\n{ 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 },\n{ 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 },\n{ 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 },\n{ 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 },\n{ 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 },\n{ 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 },\n{ 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 },\n{ 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },\n{ 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 },\n{ 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 },\n{ 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 },\n{ 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 },\n{ 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 },\n{ 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 },\n{ 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 },\n{ 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 },\n{ 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 },\n{ 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 },\n{ 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 },\n{ 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 },\n{ 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 },\n{ 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 },\n{ 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },\n{ 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 },\n{ 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },\n{ 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 },\n{ 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 },\n{ 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 },\n{ 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 },\n{ 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 },\n{ 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 },\n{ 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 },\n{ 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 },\n{ 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 },\n{ 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 },\n{ 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 },\n{ 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 },\n{ 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 },\n{ 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 },\n{ 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 },\n{ 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 },\n{ 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 },\n{ 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 },\n{ 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 },\n{ 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 },\n{ 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 },\n{ 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 },\n{ 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 },\n{ 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 },\n{ 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 },\n{ 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 },\n{ 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 },\n{ 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 },\n{ 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 },\n{ 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 },\n{ 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 },\n{ 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 },\n{ 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 },\n{ 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 },\n{ 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 },\n{ 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 },\n{ 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 },\n{ 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 },\n{ 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 },\n{ 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 },\n{ 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 },\n{ 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 },\n{ 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 },\n{ 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 },\n{ 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 },\n{ 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 },\n{ 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 },\n{ 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 },\n{ 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 },\n{ 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 },\n{ 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 },\n{ 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 },\n{ 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 },\n{ 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 },\n{ 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },\n{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } };\n\n#endif // MarchingCubesTable_h__\n"
  },
  {
    "path": "SoA/MaterialAtlas.h",
    "content": "#pragma once\n\nclass TextureAtlas {\npublic:\n\n};"
  },
  {
    "path": "SoA/MaterialData.h",
    "content": "#pragma once\n\nclass TextureData {\npublic:\n    f32 weight;\n    f32 volume;\n};"
  },
  {
    "path": "SoA/MaterialStack.h",
    "content": "#pragma once\n\nclass TextureStack {\npublic:\n    i32 id;\n    i32 count;\n};"
  },
  {
    "path": "SoA/MetaSection.cpp",
    "content": "#include \"stdafx.h\"\n#include \"MetaSection.h\""
  },
  {
    "path": "SoA/MetaSection.h",
    "content": "//\n// MetaSection.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 25 May 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Provides a method of\n//\n\n#pragma once\n\n#ifndef MetaSection_h__\n#define MetaSection_h__\n\n#include <Vorb/types.h>\n\ntypedef ui32 MetaID;\ntypedef void* MetaData;\n\n/*! @brief A description of a field in the metadata\n */\nstruct MetaFieldInformation {\n    MetaID id; ///< The unique ID of the field\n    \n    UNIT_SPACE(BYTES) size_t offset; ///< The offset of the value in the section\n    UNIT_SPACE(BYTES) size_t size; ///< The total size of the section\n\n    nString name; ///< The section's string description\n};\n\n/*! @brief Stores and keeps track of all metadata fields a metadata section will have.\n */\nclass MetaSection {\npublic:\n    template<typename T = void>\n    static T* retrieve(const MetaData& data, const MetaFieldInformation& information) {\n        return (T*)((ui8*)data + information.offset);\n    }\n\n    MetaID add(size_t s, const nString& name, size_t alignment = 1);\n    \n    MetaFieldInformation& operator[] (MetaID id);\n    const MetaFieldInformation& operator[] (MetaID id) const;\n\n    /*! @brief Retrieve the total size of the metadata section to be able to accommodate all fields.\n     * \n     * @return The total size of the section.\n     */\n    UNIT_SPACE(BYTES) const size_t& getTotalSize() const {\n        return m_size;\n    }\nprivate:\n    std::vector<MetaFieldInformation> m_fields; ///< All the fields that this metadata section contains\n    size_t m_size = 0; ///< The total size of a meta-section\n};\n\n#endif // MetaSection_h__\n"
  },
  {
    "path": "SoA/ModInformation.h",
    "content": "//\n// ModInformation.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 4 Jul 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef ModInformation_h__\n#define ModInformation_h__\n\n#include <Vorb/Event.hpp>\n\n#include \"DLLAPI.h\"\n\ntypedef Delegate<void>\n\nstruct ModInformation {\n\n\n\n    DLLAPI::Func* funcs;\n    size_t funcCount;\n};\n\n#endif // ModInformation_h__\n"
  },
  {
    "path": "SoA/ModPathResolver.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ModPathResolver.h\"\n\nvoid ModPathResolver::init(const vio::Path& defaultPath, const vio::Path& modPath) {\n    setDefaultDir(defaultPath);\n    setModDir(modPath);\n}\n\nvoid ModPathResolver::setDefaultDir(const vio::Path& path) {\n    defaultIom.setSearchDirectory(path);\n}\n\nvoid ModPathResolver::setModDir(const vio::Path& path) {\n    modIom.setSearchDirectory(path);\n}\n\nbool ModPathResolver::resolvePath(const vio::Path& path, vio::Path& resultAbsolutePath, bool printModNotFound /* = false */) const {\n    if (!modIom.resolvePath(path, resultAbsolutePath)) {\n        if (printModNotFound) {\n            printf(\"Did not find path %s in %s.\", path.getCString(), modIom.getSearchDirectory().getCString());\n        }\n        if (!defaultIom.resolvePath(path, resultAbsolutePath)) {\n            if (printModNotFound) {\n                printf(\"Did not find path %s in %s.\", path.getCString(), defaultIom.getSearchDirectory().getCString());\n            }\n            return false;\n        }\n    }\n    return true;\n}\n"
  },
  {
    "path": "SoA/ModPathResolver.h",
    "content": "///\n/// ModPathResolver.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 19 Apr 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Resolves file paths for mod files by first looking in \n/// a mod folder, then a default if it fails.\n///\n\n#pragma once\n\n#ifndef ModPathResolver_h__\n#define ModPathResolver_h__\n\n#include <Vorb/io/IOManager.h>\n\nclass ModPathResolver {\npublic:\n    /// Initialization\n    void init(const vio::Path& defaultPath, const vio::Path& modPath);\n    /// Sets directory for defaults\n    void setDefaultDir(const vio::Path& path);\n    /// Sets directory for mods\n    void setModDir(const vio::Path& path);\n    /// Gets the absolute path. If not in Mod, checks in default.\n    /// @return false on failure\n    bool resolvePath(const vio::Path& path, vio::Path& resultAbsolutePath, bool printModNotFound = false) const;\n\n    vio::IOManager defaultIom;\n    vio::IOManager modIom;\n};\n\n#endif // ModPathResolver_h__\n"
  },
  {
    "path": "SoA/ModelMesher.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ModelMesher.h\"\n\n#include \"VoxelMatrix.h\"\n#include \"VoxelModel.h\"\n#include \"VoxelModelMesh.h\"\n#include \"MarchingCubesTable.h\"\n#include \"DualContouringMesher.h\"\n\n#include <vector>\n\nconst f32v3 VOXEL_MODEL[24] = {\n    f32v3(0, 1, 0),\n    f32v3(0, 1, 1),\n    f32v3(0, 0, 0),\n    f32v3(0, 0, 1),\n\n    f32v3(1, 1, 1),\n    f32v3(1, 1, 0),\n    f32v3(1, 0, 1),\n    f32v3(1, 0, 0),\n\n    f32v3(0, 0, 1),\n    f32v3(1, 0, 1),\n    f32v3(0, 0, 0),\n    f32v3(1, 0, 0),\n\n    f32v3(0, 1, 0),\n    f32v3(1, 1, 0),\n    f32v3(0, 1, 1),\n    f32v3(1, 1, 1),\n\n    f32v3(1, 1, 0),\n    f32v3(0, 1, 0),\n    f32v3(1, 0, 0),\n    f32v3(0, 0, 0),\n\n    f32v3(0, 1, 1),\n    f32v3(1, 1, 1),\n    f32v3(0, 0, 1),\n    f32v3(1, 0, 1)\n};\n\nconst ui32 VOXEL_INDICES[6] = {\n    0, 2, 1,\n    1, 2, 3\n};\n\nconst i32v3 VOXEL_SIDES[6] = {\n    i32v3(-1, 0, 0),\n    i32v3(1, 0, 0),\n    i32v3(0, -1, 0),\n    i32v3(0, 1, 0),\n    i32v3(0, 0, -1),\n    i32v3(0, 0, 1),\n};\n\nVoxelModelMesh ModelMesher::createMesh(const VoxelModel* model) {\n    std::vector<VoxelModelVertex> vertices;\n    std::vector<ui32> indices;\n    VoxelModelMesh rv;\n    \n    genMatrixMesh(model->getMatrix(), vertices, indices);\n\n    if (indices.size() == 0) return rv;\n\n    glGenVertexArrays(1, &rv.m_vao);\n    glBindVertexArray(rv.m_vao);\n\n    glGenBuffers(1, &rv.m_vbo);\n    glBindBuffer(GL_ARRAY_BUFFER, rv.m_vbo);\n    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VoxelModelVertex), vertices.data(), GL_STATIC_DRAW);\n    \n    rv.m_indCount = indices.size();\n    rv.m_triCount = (indices.size() * 2) / 6;\n    glGenBuffers(1, &rv.m_ibo);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rv.m_ibo);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, rv.m_indCount * sizeof(ui32), indices.data(), GL_STATIC_DRAW);\n\n    glBindVertexArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    glBindVertexArray(rv.m_vao);\n    glBindBuffer(GL_ARRAY_BUFFER, rv.m_vbo);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rv.m_ibo);\n    glBindVertexArray(0);\n    // THIS CAUSES CRASH v v v\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    return rv;\n}\n\nVoxelModelMesh ModelMesher::createMarchingCubesMesh(const VoxelModel* model) {\n    std::vector<VoxelModelVertex> vertices;\n    std::vector<ui32> indices;\n    VoxelModelMesh rv;\n\n    auto& matrix = model->getMatrix();\n\n    // This constructs a potential (density) field from our voxel data, with points at the corner of each voxel\n    f32v4* points = new f32v4[(matrix.size.x + 1) * (matrix.size.y + 1) * (matrix.size.z + 1)];\n    int index = 0;\n    // + 1 since its the corner points intead of the actual voxels (for smoother mesh)\n    for (ui32 x = 0; x < matrix.size.x + 1; x++) {\n        for (ui32 y = 0; y < matrix.size.y + 1; y++) {\n            for (ui32 z = 0; z < matrix.size.z + 1; z++) {\n                f32v4 vert(x, y, z, 0);\n                // Gets the potential\n                vert.w = getMarchingPotential(matrix, x, y, z);\n               \n                points[x * (matrix.size.y + 1) * (matrix.size.z + 1) + y * (matrix.size.z + 1) + z] = vert;\n                index++;\n            }\n        }\n    }\n\n    marchingCubes(matrix, 1.0f, 1.0f, 1.0f, 0.5f, points, vertices);\n\n    // TODO(Ben): Indexed drawing\n    rv.m_triCount = vertices.size() / 3;\n    delete[] points;\n\n    glGenVertexArrays(1, &rv.m_vao);\n    glBindVertexArray(rv.m_vao);\n\n    glGenBuffers(1, &rv.m_vbo);\n    glBindBuffer(GL_ARRAY_BUFFER, rv.m_vbo);\n    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VoxelModelVertex), vertices.data(), GL_STATIC_DRAW);\n\n    rv.m_indCount = 0;\n    glGenBuffers(1, &rv.m_ibo);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rv.m_ibo);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, rv.m_indCount * sizeof(ui32), indices.data(), GL_STATIC_DRAW);\n\n    glBindVertexArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    glBindVertexArray(rv.m_vao);\n    glBindBuffer(GL_ARRAY_BUFFER, rv.m_vbo);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rv.m_ibo);\n    glBindVertexArray(0);\n    // THIS CAUSES CRASH v v v\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    return rv;\n}\n\nVoxelModelMesh ModelMesher::createDualContouringMesh(const VoxelModel* model) {\n    std::vector<VoxelModelVertex> vertices;\n    std::vector<ui32> indices;\n    VoxelModelMesh rv;\n\n    DualContouringMesher::genMatrixMesh(model->getMatrix(), vertices, indices);\n\n    if (indices.size() == 0) return rv;\n\n    glGenVertexArrays(1, &rv.m_vao);\n    glBindVertexArray(rv.m_vao);\n\n    glGenBuffers(1, &rv.m_vbo);\n    glBindBuffer(GL_ARRAY_BUFFER, rv.m_vbo);\n    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VoxelModelVertex), vertices.data(), GL_STATIC_DRAW);\n\n    rv.m_indCount = indices.size();\n    rv.m_triCount = (indices.size() * 2) / 6;\n    glGenBuffers(1, &rv.m_ibo);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rv.m_ibo);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, rv.m_indCount * sizeof(ui32), indices.data(), GL_STATIC_DRAW);\n\n    glBindVertexArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    glBindVertexArray(rv.m_vao);\n    glBindBuffer(GL_ARRAY_BUFFER, rv.m_vbo);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rv.m_ibo);\n    glBindVertexArray(0);\n    // THIS CAUSES CRASH v v v\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    return rv;\n}\n\n// Gets the potential at voxel corners\nf32 ModelMesher::getMarchingPotential(const VoxelMatrix& matrix, int x, int y, int z) {\n\n    // TODO: This could all be written from scratch. Not sure the best way to go about it.\n\n    f32 potential = 0.0f;\n    const int FILTER_SIZE = 2; ///< Should be at least 2\n    const int HALF_FILTER_SIZE = FILTER_SIZE / 2;\n    x -= HALF_FILTER_SIZE;\n    y -= HALF_FILTER_SIZE;\n    z -= HALF_FILTER_SIZE;\n\n    // We use a 2x2x2 filter of voxels around a given voxel corner point\n    for (int i = 0; i < FILTER_SIZE; i++) {\n        for (int j = 0; j < FILTER_SIZE; j++) {\n            for (int k = 0; k < FILTER_SIZE; k++) {\n                // TODO: Play with this!\n\n                if (matrix.getColorAndCheckBounds(x + i, y + j, z + k).a != 0) {\n                    potential += 1.0f;\n                }\n                // Interesting effect:\n                /* float dx = abs(i - 1.5f);\n                 float dy = abs(j - 1.5f);\n                 float dz = abs(k - 1.5f);\n                 if (matrix.getColorAndCheckBounds(x + i, y + j, z + k).a != 0) {\n                 if (dx <= 0.75f && dy <= 0.75f && dz <= 0.75f) {\n                 potential += 2.0f;\n                 } else {\n                 potential += 0.75f;\n                 }\n                 } else if (dx <= 0.75f && dy <= 0.75f && dz <= 0.75f) {\n                 potential -= 2.0f;\n                 }*/\n            }\n        }\n    }\n    // Average the samples\n    return potential / (FILTER_SIZE * FILTER_SIZE * FILTER_SIZE);\n\n    if (matrix.getColor(x, y, z).a != 0.0) {\n        potential += 2.0f;\n    }\n\n    // Add extra potential from neighbors ( makes it smoother )\n    // When .a is 0.0, that is an air block\n    if (matrix.getColorAndCheckBounds(x - 1, y, z).a != 0.0) {\n        potential += 0.25f;\n    }\n    if (matrix.getColorAndCheckBounds(x + 1, y, z).a != 0.0) {\n        potential += 0.25f;\n    }\n    if (matrix.getColorAndCheckBounds(x, y - 1, z).a != 0.0) {\n        potential += 0.25f;\n    }\n    if (matrix.getColorAndCheckBounds(x, y + 1, z).a != 0.0) {\n        potential += 0.25f;\n    }\n    if (matrix.getColorAndCheckBounds(x, y, z - 1).a != 0.0) {\n        potential += 0.25f;\n    }\n    if (matrix.getColorAndCheckBounds(x, y, z + 1).a != 0.0) {\n        potential += 0.25f;\n    }\n\n    // Divide by 7 to average with neighbors a bit\n    return potential / 7.0f;\n}\n\n// This gets color for marching cubes vertices by averaging nearby voxel colors\n// TODO: Figure out a metter method?\ncolor3 ModelMesher::getColor(const f32v3& pos, const VoxelMatrix& matrix) {\n    ui32v3 ipos(glm::round(pos));\n    if (ipos.x >= matrix.size.x) ipos.x = matrix.size.x - 1;\n    if (ipos.y >= matrix.size.y) ipos.y = matrix.size.y - 1;\n    if (ipos.z >= matrix.size.z) ipos.z = matrix.size.z - 1;\n    ui32 x = ipos.x;\n    ui32 y = ipos.y;\n    ui32 z = ipos.z;\n\n    int numColors = 0;\n    i32v3 fColor(0);\n\n    if (y > 0) {\n        if (z > 0) {\n            // Bottom back left\n            if (x > 0) {\n                color4 color = matrix.getColor(x - 1, y - 1, z - 1);\n                if (color.a != 0 && !matrix.isInterior(x - 1, y - 1, z - 1)) {\n                    numColors++;\n                    fColor.r += color.r;\n                    fColor.g += color.g;\n                    fColor.b += color.b;\n                }\n            }\n            // Bottom back right\n            if (x < matrix.size.x) {\n                color4 color = matrix.getColor(x, y - 1, z - 1);\n                if (color.a != 0 && !matrix.isInterior(x, y - 1, z - 1)) {\n                    numColors++;\n                    fColor.r += color.r;\n                    fColor.g += color.g;\n                    fColor.b += color.b;\n                }\n            }\n        }\n        if (z < matrix.size.z) {\n            // Bottom front left\n            if (x > 0) {\n                color4 color = matrix.getColor(x - 1, y - 1, z);\n                if (color.a != 0 && !matrix.isInterior(x - 1, y - 1, z)) {\n                    numColors++;\n                    fColor.r += color.r;\n                    fColor.g += color.g;\n                    fColor.b += color.b;\n                }\n            }\n            // Bottom front right\n            if (x < matrix.size.x) {\n                color4 color = matrix.getColor(x, y - 1, z);\n                if (color.a != 0 && !matrix.isInterior(x, y - 1, z)) {\n                    numColors++;\n                    fColor.r += color.r;\n                    fColor.g += color.g;\n                    fColor.b += color.b;\n                }\n            }\n        }\n\n    }\n\n    if (y < matrix.size.y) {\n        if (z > 0) {\n            // Top back left\n            if (x > 0) {\n                color4 color = matrix.getColor(x - 1, y, z - 1);\n                if (color.a != 0 && !matrix.isInterior(x - 1, y, z - 1)) {\n                    numColors++;\n                    fColor.r += color.r;\n                    fColor.g += color.g;\n                    fColor.b += color.b;\n                }\n            }\n            // Top back right\n            if (x < matrix.size.x) {\n                color4 color = matrix.getColor(x, y, z - 1);\n                if (color.a != 0 && !matrix.isInterior(x, y, z - 1)) {\n                    numColors++;\n                    fColor.r += color.r;\n                    fColor.g += color.g;\n                    fColor.b += color.b;\n                }\n            }\n        }\n        if (z < matrix.size.z) {\n            // Top front left\n            if (x > 0) {\n                color4 color = matrix.getColor(x - 1, y, z);\n                if (color.a != 0 && !matrix.isInterior(x - 1, y, z)) {\n                    numColors++;\n                    fColor.r += color.r;\n                    fColor.g += color.g;\n                    fColor.b += color.b;\n                }\n            }\n            // Top front right\n            if (x < matrix.size.x) {\n                color4 color = matrix.getColor(x, y, z);\n                if (color.a != 0 && !matrix.isInterior(x, y, z)) {\n                    numColors++;\n                    fColor.r += color.r;\n                    fColor.g += color.g;\n                    fColor.b += color.b;\n                }\n            }\n        }\n    }\n    if (numColors) {\n        fColor /= numColors;\n    }\n\n    return color3(fColor.r, fColor.g, fColor.b);\n}\n\ncolor3 ModelMesher::getColor2(const i32v3& pos, const VoxelMatrix& matrix) {\n    int numColors = 1;\n    i32v3 fColor(0);\n\n    { // Center\n        color4 vColor = matrix.getColorAndCheckBounds(pos);\n        if (vColor.a != 0 && !matrix.isInterior(pos)) {\n            return vColor.color.rgb;\n        }\n    }\n    { // Left\n        i32v3 vPos = pos + i32v3(-1, 0, 0);\n        color4 vColor = matrix.getColorAndCheckBounds(vPos);\n        if (vColor.a != 0 && !matrix.isInterior(vPos)) {\n            return vColor.color.rgb;\n        }\n    }\n    { // Right\n        i32v3 vPos = pos + i32v3(1, 0, 0);\n        color4 vColor = matrix.getColorAndCheckBounds(vPos);\n        if (vColor.a != 0 && !matrix.isInterior(vPos)) {\n            return vColor.color.rgb;\n        }\n    }\n    { // Bottom\n        i32v3 vPos = pos + i32v3(0, -1, 0);\n        color4 vColor = matrix.getColorAndCheckBounds(vPos);\n        if (vColor.a != 0 && !matrix.isInterior(vPos)) {\n            return vColor.color.rgb;\n        }\n    }\n    { // Top\n        i32v3 vPos = pos + i32v3(0, 1, 0);\n        color4 vColor = matrix.getColorAndCheckBounds(vPos);\n        if (vColor.a != 0 && !matrix.isInterior(vPos)) {\n            return vColor.color.rgb;\n        }\n    }\n    { // Back\n        i32v3 vPos = pos + i32v3(0, 0, -1);\n        color4 vColor = matrix.getColorAndCheckBounds(vPos);\n        if (vColor.a != 0 && !matrix.isInterior(vPos)) {\n            return vColor.color.rgb;\n        }\n    }\n    { // Front\n        i32v3 vPos = pos + i32v3(0, 0, 1);\n        color4 vColor = matrix.getColorAndCheckBounds(vPos);\n        if (vColor.a != 0 && !matrix.isInterior(vPos)) {\n            return vColor.color.rgb;\n        }\n    }\n    return color3(0, 0, 0);\n    if (numColors) {\n        fColor /= numColors;\n    }\n\n    return color3(fColor.r, fColor.g, fColor.b);\n}\n\n//Macros used to compute gradient vector on each vertex of a cube\n//argument should be the name of array of vertices\n//can be verts or *verts if done by reference\n#define CALC_GRAD_VERT_0(verts) f32v4(points[ind-YtimeZ].w-(verts[1]).w,points[ind-pointsZ].w-(verts[4]).w,points[ind-1].w-(verts[3]).w, (verts[0]).w);\n#define CALC_GRAD_VERT_1(verts) f32v4((verts[0]).w-points[ind+2*YtimeZ].w,points[ind+YtimeZ-pointsZ].w-(verts[5]).w,points[ind+YtimeZ-1].w-(verts[2]).w, (verts[1]).w);\n#define CALC_GRAD_VERT_2(verts) f32v4((verts[3]).w-points[ind+2*YtimeZ+1].w,points[ind+YtimeZ-ncellsZ].w-(verts[6]).w,(verts[1]).w-points[ind+YtimeZ+2].w, (verts[2]).w);\n#define CALC_GRAD_VERT_3(verts) f32v4(points[ind-YtimeZ+1].w-(verts[2]).w,points[ind-ncellsZ].w-(verts[7]).w,(verts[0]).w-points[ind+2].w, (verts[3]).w);\n#define CALC_GRAD_VERT_4(verts) f32v4(points[ind-YtimeZ+ncellsZ+1].w-(verts[5]).w,(verts[0]).w-points[ind+2*pointsZ].w,points[ind+ncellsZ].w-(verts[7]).w, (verts[4]).w);\n#define CALC_GRAD_VERT_5(verts) f32v4((verts[4]).w-points[ind+2*YtimeZ+ncellsZ+1].w,(verts[1]).w-points[ind+YtimeZ+2*pointsZ].w,points[ind+YtimeZ+ncellsZ].w-(verts[6]).w, (verts[5]).w);\n#define CALC_GRAD_VERT_6(verts) f32v4((verts[7]).w-points[ind+2*YtimeZ+ncellsZ+2].w,(verts[2]).w-points[ind+YtimeZ+2*ncellsZ+3].w,(verts[5]).w-points[ind+YtimeZ+ncellsZ+3].w, (verts[6]).w);\n#define CALC_GRAD_VERT_7(verts) f32v4(points[ind-YtimeZ+ncellsZ+2].w-(verts[6]).w,(verts[3]).w-points[ind+2*ncellsZ+3].w,(verts[4]).w-points[ind+ncellsZ+3].w, (verts[7]).w);\n\n///////////////////////////////////////////////////////////////////////////////////////////////////////\n// GLOBAL //\n//Global variables - so they dont have to be passed into functions\nint pointsZ;\t//number of points on Z zxis (equal to ncellsZ+1)\nint YtimeZ;\t\t//'plane' of cubes on YZ (equal to (ncellsY+1)*pointsZ )\n///////////////////////////////////////////////////////////////////////////////////////////////////////\n\n//Linear Interpolation between two points\nf32v3 linearInterp(const f32v4& p1, const f32v4& p2, float value) {\n    f32v3 p13(p1);\n    if (fabs(p1.w - p2.w) > 0.00001f)\n        return p13 + (f32v3(p2) - p13) / (p2.w - p1.w)*(value - p1.w);\n    else\n        return p13;\n}\n\n\n// Source: http://www.angelfire.com/linux/myp/MC/\n// With Improvements: http://www.angelfire.com/linux/myp/MCAdvanced/MCImproved.html\nvoid ModelMesher::marchingCubes(const VoxelMatrix& matrix,\n                                float gradFactorX, float gradFactorY, float gradFactorZ,\n                                float minValue, f32v4 * points, std::vector<VoxelModelVertex>& vertices) {\n    int ncellsX = matrix.size.x;\n    int ncellsY = matrix.size.y;\n    int ncellsZ = matrix.size.z;\n\n    pointsZ = ncellsZ + 1;\t\t\t//initialize global variable (for extra speed) \n    YtimeZ = (ncellsY + 1)*pointsZ;\n\n    f32v4 *verts[8];\t\t\t//vertices of a cube (array of pointers for extra speed)\n    f32v3 intVerts[12];\t\t\t//linearly interpolated vertices on each edge\n    int cubeIndex;\t\t\t\t\t//shows which vertices are outside/inside\n    int edgeIndex;\t\t\t\t\t//index returned by edgeTable[cubeIndex]\n    f32v4 gradVerts[8];\t\t\t//gradients at each vertex of a cube\t\t\n    f32v3 grads[12];\t\t\t\t//linearly interpolated gradients on each edge\n    int indGrad;\t\t\t\t\t//shows which gradients already have been computed\n    int ind, ni, nj;\t\t\t\t//ind: index of vertex 0\n    //factor by which corresponding coordinates of gradient vectors are scaled\n    f32v3 factor(1.0f / (2.0*gradFactorX), 1.0f / (2.0*gradFactorY), 1.0f / (2.0*gradFactorZ));\n\n    f32v3 mainOffset(-(matrix.size.x / 2.0f), -(matrix.size.y / 2.0f), -(matrix.size.z / 2.0f));\n\n    //MAIN LOOP: goes through all the points\n    for (int i = 0; i < ncellsX; i++) {\t\t\t//x axis\n        ni = i*YtimeZ;\n        for (int j = 0; j < ncellsY; j++) {\t\t//y axis\n            nj = j*pointsZ;\n            for (int k = 0; k < ncellsZ; k++, ind++)\t//z axis\n            {\n                //initialize vertices\n                ind = ni + nj + k;\n                verts[0] = &points[ind];\n                verts[1] = &points[ind + YtimeZ];\n                verts[4] = &points[ind + pointsZ];\n                verts[5] = &points[ind + YtimeZ + pointsZ];\n                verts[2] = &points[ind + YtimeZ + 1];\n                verts[3] = &points[ind + 1];\n                verts[6] = &points[ind + YtimeZ + pointsZ + 1];\n                verts[7] = &points[ind + pointsZ + 1];\n\n                //get the index\n                cubeIndex = int(0);\n                for (int n = 0; n < 8; n++)\n                    if (verts[n]->w <= minValue) cubeIndex |= (1 << n);\n\n                //check if its completely inside or outside\n                if (!edgeTable[cubeIndex]) continue;\n\n                indGrad = int(0);\n                edgeIndex = edgeTable[cubeIndex];\n\n                if (edgeIndex & 1) {\n                    intVerts[0] = linearInterp(*verts[0], *verts[1], minValue);\n                    if (i != 0 && j != 0 && k != 0) gradVerts[0] = CALC_GRAD_VERT_0(*verts)\n                    else gradVerts[0] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                    if (i != ncellsX - 1 && j != 0 && k != 0) gradVerts[1] = CALC_GRAD_VERT_1(*verts)\n                    else gradVerts[1] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                    indGrad |= 3;\n                    grads[0] = linearInterp(gradVerts[0], gradVerts[1], minValue);\n                    grads[0].x *= factor.x; grads[0].y *= factor.y; grads[0].z *= factor.z;\n                }\n                if (edgeIndex & 2) {\n                    intVerts[1] = linearInterp(*verts[1], *verts[2], minValue);\n                    if (!(indGrad & 2)) {\n                        if (i != ncellsX - 1 && j != 0 && k != 0) gradVerts[1] = CALC_GRAD_VERT_1(*verts)\n                        else gradVerts[1] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 2;\n                    }\n                    if (i != ncellsX - 1 && j != 0 && k != 0) gradVerts[2] = CALC_GRAD_VERT_2(*verts)\n                    else gradVerts[2] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                    indGrad |= 4;\n                    grads[1] = linearInterp(gradVerts[1], gradVerts[2], minValue);\n                    grads[1].x *= factor.x; grads[1].y *= factor.y; grads[1].z *= factor.z;\n                }\n                if (edgeIndex & 4) {\n                    intVerts[2] = linearInterp(*verts[2], *verts[3], minValue);\n                    if (!(indGrad & 4)) {\n                        if (i != ncellsX - 1 && j != 0 && k != 0) gradVerts[2] = CALC_GRAD_VERT_2(*verts)\n                        else gradVerts[2] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 4;\n                    }\n                    if (i != 0 && j != 0 && k != ncellsZ - 1) gradVerts[3] = CALC_GRAD_VERT_3(*verts)\n                    else gradVerts[3] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                    indGrad |= 8;\n                    grads[2] = linearInterp(gradVerts[2], gradVerts[3], minValue);\n                    grads[2].x *= factor.x; grads[2].y *= factor.y; grads[2].z *= factor.z;\n                }\n                if (edgeIndex & 8) {\n                    intVerts[3] = linearInterp(*verts[3], *verts[0], minValue);\n                    if (!(indGrad & 8)) {\n                        if (i != 0 && j != 0 && k != ncellsZ - 1) gradVerts[3] = CALC_GRAD_VERT_3(*verts)\n                        else gradVerts[3] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 8;\n                    }\n                    if (!(indGrad & 1)) {\n                        if (i != 0 && j != 0 && k != 0) gradVerts[0] = CALC_GRAD_VERT_0(*verts)\n                        else gradVerts[0] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 1;\n                    }\n                    grads[3] = linearInterp(gradVerts[3], gradVerts[0], minValue);\n                    grads[3].x *= factor.x; grads[3].y *= factor.y; grads[3].z *= factor.z;\n                }\n                if (edgeIndex & 16) {\n                    intVerts[4] = linearInterp(*verts[4], *verts[5], minValue);\n\n                    if (i != 0 && j != ncellsY - 1 && k != 0) gradVerts[4] = CALC_GRAD_VERT_4(*verts)\n                    else gradVerts[4] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n\n                    if (i != ncellsX - 1 && j != ncellsY - 1 && k != 0) gradVerts[5] = CALC_GRAD_VERT_5(*verts)\n                    else gradVerts[5] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n\n                    indGrad |= 48;\n                    grads[4] = linearInterp(gradVerts[4], gradVerts[5], minValue);\n                    grads[4].x *= factor.x; grads[4].y *= factor.y; grads[4].z *= factor.z;\n                }\n                if (edgeIndex & 32) {\n                    intVerts[5] = linearInterp(*verts[5], *verts[6], minValue);\n                    if (!(indGrad & 32)) {\n                        if (i != ncellsX - 1 && j != ncellsY - 1 && k != 0) gradVerts[5] = CALC_GRAD_VERT_5(*verts)\n                        else gradVerts[5] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 32;\n                    }\n\n                    if (i != ncellsX - 1 && j != ncellsY - 1 && k != ncellsZ - 1) gradVerts[6] = CALC_GRAD_VERT_6(*verts)\n                    else gradVerts[6] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                    indGrad |= 64;\n                    grads[5] = linearInterp(gradVerts[5], gradVerts[6], minValue);\n                    grads[5].x *= factor.x; grads[5].y *= factor.y; grads[5].z *= factor.z;\n                }\n                if (edgeIndex & 64) {\n                    intVerts[6] = linearInterp(*verts[6], *verts[7], minValue);\n                    if (!(indGrad & 64)) {\n                        if (i != ncellsX - 1 && j != ncellsY - 1 && k != ncellsZ - 1) gradVerts[6] = CALC_GRAD_VERT_6(*verts)\n                        else gradVerts[6] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 64;\n                    }\n\n                    if (i != 0 && j != ncellsY - 1 && k != ncellsZ - 1) gradVerts[7] = CALC_GRAD_VERT_7(*verts)\n                    else gradVerts[7] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                    indGrad |= 128;\n                    grads[6] = linearInterp(gradVerts[6], gradVerts[7], minValue);\n                    grads[6].x *= factor.x; grads[6].y *= factor.y; grads[6].z *= factor.z;\n                }\n                if (edgeIndex & 128) {\n                    intVerts[7] = linearInterp(*verts[7], *verts[4], minValue);\n                    if (!(indGrad & 128)) {\n                        if (i != 0 && j != ncellsY - 1 && k != ncellsZ - 1) gradVerts[7] = CALC_GRAD_VERT_7(*verts)\n                        else gradVerts[7] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 128;\n                    }\n                    if (!(indGrad & 16)) {\n                        if (i != 0 && j != ncellsY - 1 && k != 0) gradVerts[4] = CALC_GRAD_VERT_4(*verts)\n                        else gradVerts[4] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 16;\n                    }\n                    grads[7] = linearInterp(gradVerts[7], gradVerts[4], minValue);\n                    grads[7].x *= factor.x; grads[7].y *= factor.y; grads[7].z *= factor.z;\n                }\n                if (edgeIndex & 256) {\n                    intVerts[8] = linearInterp(*verts[0], *verts[4], minValue);\n                    if (!(indGrad & 1)) {\n                        if (i != 0 && j != 0 && k != 0) gradVerts[0] = CALC_GRAD_VERT_0(*verts)\n                        else gradVerts[0] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 1;\n                    }\n                    if (!(indGrad & 16)) {\n                        if (i != 0 && j != ncellsY - 1 && k != 0) gradVerts[4] = CALC_GRAD_VERT_4(*verts)\n                        else gradVerts[4] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 16;\n                    }\n                    grads[8] = linearInterp(gradVerts[0], gradVerts[4], minValue);\n                    grads[8].x *= factor.x; grads[8].y *= factor.y; grads[8].z *= factor.z;\n                }\n                if (edgeIndex & 512) {\n                    intVerts[9] = linearInterp(*verts[1], *verts[5], minValue);\n                    if (!(indGrad & 2)) {\n                        if (i != ncellsX - 1 && j != 0 && k != 0) gradVerts[1] = CALC_GRAD_VERT_1(*verts)\n                        else gradVerts[1] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 2;\n                    }\n                    if (!(indGrad & 32)) {\n                        if (i != ncellsX - 1 && j != ncellsY - 1 && k != 0) gradVerts[5] = CALC_GRAD_VERT_5(*verts)\n                        else gradVerts[5] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 32;\n                    }\n                    grads[9] = linearInterp(gradVerts[1], gradVerts[5], minValue);\n                    grads[9].x *= factor.x; grads[9].y *= factor.y; grads[9].z *= factor.z;\n                }\n                if (edgeIndex & 1024) {\n                    intVerts[10] = linearInterp(*verts[2], *verts[6], minValue);\n                    if (!(indGrad & 4)) {\n                        if (i != ncellsX - 1 && j != 0 && k != 0) gradVerts[2] = CALC_GRAD_VERT_2(*verts)\n                        else gradVerts[5] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 4;\n                    }\n                    if (!(indGrad & 64)) {\n                        if (i != ncellsX - 1 && j != ncellsY - 1 && k != ncellsZ - 1) gradVerts[6] = CALC_GRAD_VERT_6(*verts)\n                        else gradVerts[6] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 64;\n                    }\n                    grads[10] = linearInterp(gradVerts[2], gradVerts[6], minValue);\n                    grads[10].x *= factor.x; grads[10].y *= factor.y; grads[10].z *= factor.z;\n                }\n                if (edgeIndex & 2048) {\n                    intVerts[11] = linearInterp(*verts[3], *verts[7], minValue);\n                    if (!(indGrad & 8)) {\n                        if (i != 0 && j != 0 && k != ncellsZ - 1) gradVerts[3] = CALC_GRAD_VERT_3(*verts)\n                        else gradVerts[3] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 8;\n                    }\n                    if (!(indGrad & 128)) {\n                        if (i != 0 && j != ncellsY - 1 && k != ncellsZ - 1) gradVerts[7] = CALC_GRAD_VERT_7(*verts)\n                        else gradVerts[7] = f32v4(1.0f, 1.0f, 1.0f, 1.0f);\n                        indGrad |= 128;\n                    }\n                    grads[11] = linearInterp(gradVerts[3], gradVerts[7], minValue);\n                    grads[11].x *= factor.x; grads[11].y *= factor.y; grads[11].z *= factor.z;\n                }\n\n                //now build the triangles using triTable\n                for (int n = 0; triTable[cubeIndex][n] != -1; n += 3) {\n                    int index[3] = { triTable[cubeIndex][n + 2], triTable[cubeIndex][n + 1], triTable[cubeIndex][n] };\n                    int startVertex = vertices.size();\n                    vertices.resize(vertices.size() + 3);\n                    for (int h = 0; h < 3; h++) {\n                        vertices[startVertex + h].color = getColor(intVerts[index[h]], matrix);\n                        vertices[startVertex + h].pos = intVerts[index[h]] + mainOffset;\n                        vertices[startVertex + h].normal = grads[index[h]];\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid ModelMesher::genMatrixMesh(const VoxelMatrix& matrix, std::vector<VoxelModelVertex>& vertices, std::vector<ui32>& indices) {\n    // TODO(Ben): Could be optimized\n    f32v3 mainOffset(matrix.size.x / 2.0f, matrix.size.y / 2.0f, matrix.size.z / 2.0f);\n    int voxelIndex;\n    for(ui32 z = 0; z < matrix.size.z; z++) {\n        for (ui32 y = 0; y < matrix.size.y; y++) {\n            for (ui32 x = 0; x < matrix.size.x; x++) {\n                voxelIndex = matrix.getIndex(x, y, z);\n                const ColorRGBA8& voxel = matrix.getColor(voxelIndex); // Get the current voxel's color\n                if(voxel.a == 0) continue; // If the current voxel is invisible go to next voxel\n\n                f32v3 offset = f32v3(x, y, z) - mainOffset; // Position of the current voxel in the model\n                for (int face = 0; face < 6; face++) { // For each face of the voxel\n                    if(matrix.getColorAndCheckBounds(i32v3(x, y, z) + VOXEL_SIDES[face]).a == 0) { // Check if the adjacent voxel is invisible\n                        int indexStart = (int)vertices.size();\n                        int indiceStart = (int)indices.size();\n\n                        // Add the 4 vertices for this face\n                        vertices.resize(indexStart + 4);\n                        for (int l = 0; l < 4; l++) {\n                            vertices[indexStart + l].pos = offset + VOXEL_MODEL[face * 4 + l];\n                            vertices[indexStart + l].color = voxel.color.rgb;\n                            vertices[indexStart + l].normal = f32v3(VOXEL_SIDES[face]);\n                        }\n\n                        // Add the 6 indices for this face\n                        indices.resize(indiceStart + 6);\n                        indices[indiceStart] = indexStart + VOXEL_INDICES[0];\n                        indices[indiceStart + 1] = indexStart + VOXEL_INDICES[1];\n                        indices[indiceStart + 2] = indexStart + VOXEL_INDICES[2];\n                        indices[indiceStart + 3] = indexStart + VOXEL_INDICES[3];\n                        indices[indiceStart + 4] = indexStart + VOXEL_INDICES[4];\n                        indices[indiceStart + 5] = indexStart + VOXEL_INDICES[5];\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "SoA/ModelMesher.h",
    "content": "#pragma once\n#ifndef ModelMesher_h__\n#define ModelMesher_h__\n\n#include <Vorb/types.h>\n\nclass VoxelMatrix;\nclass VoxelModel;\nclass VoxelModelMesh;\nclass VoxelModelVertex;\n\nclass ModelMesher {\npublic:\n    static VoxelModelMesh createMesh(const VoxelModel* model);\n    static VoxelModelMesh createMarchingCubesMesh(const VoxelModel* model);\n    static VoxelModelMesh createDualContouringMesh(const VoxelModel* model);\nprivate:\n    // *** Regular ***\n    static void genMatrixMesh(const VoxelMatrix& matrix, std::vector<VoxelModelVertex>& vertices, std::vector<ui32>& indices);\n\n    // *** Marching Cubes ***\n    static color3 getColor(const f32v3& pos, const VoxelMatrix& matrix);\n    static color3 getColor2(const i32v3& pos, const VoxelMatrix& matrix);\n    static void marchingCubes(const VoxelMatrix& matrix,\n                              float gradFactorX, float gradFactorY, float gradFactorZ,\n                              float minValue, f32v4 * points, std::vector<VoxelModelVertex>& vertices);\n    static f32 getMarchingPotential(const VoxelMatrix& matrix, int x, int y, int z);\n};\n\n#endif //ModelMesher_h__"
  },
  {
    "path": "SoA/MusicPlayer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"MusicPlayer.h\"\n\n#include <Vorb/IO.h>\n#include <Vorb/sound/SoundEngine.h>\n\n\n#include \"SoaFileSystem.h\"\n\nvoid MusicPlayer::refreshLists(const SoaFileSystem& fs) {\n    // Kill current lists\n    m_music.clear();\n    m_playlists.clear();\n\n    // Check for the music folder\n    const vpath& musicPath = fs.get(\"Music\").getSearchDirectory();\n    if (!musicPath.isValid()) {\n        // Create the folder and then exit\n        vio::buildDirectoryTree(musicPath);\n        return;\n    }\n\n    vdir musicDir;\n    if (!musicPath.asDirectory(&musicDir)) {\n        // What happened here...\n        return;\n    }\n    searchTree(musicDir);\n}\n\nvoid MusicPlayer::begin(vsound::Engine& engine VORB_MAYBE_UNUSED) {\n    if (m_isRunning) return;\n    m_isRunning = true;\n}\nvoid MusicPlayer::stop() {\n    if (!m_isRunning) return;\n    m_isRunning = false;\n}\n\ninline bool strEndsWith(const nString& value, const nString& ending) {\n    if (ending.size() > value.size()) return false;\n    return std::equal(ending.rbegin(), ending.rend(), value.rbegin());\n}\nvoid MusicPlayer::searchTree(const vdir& root) {\n    root.forEachEntry([&] (Sender s VORB_MAYBE_UNUSED, const vpath& p) {\n        if (p.isFile()) {\n            nString fileName = p.getLeaf();\n            if (strEndsWith(fileName, \".mp3\")) {\n                m_music.push_back(p);\n                printf(\"Found Music: %s\\n\", fileName.c_str());\n            } else if (strEndsWith(fileName, \".ogg\")) {\n                m_music.push_back(p);\n                printf(\"Found Music: %s\\n\", fileName.c_str());\n            } else if (strEndsWith(fileName, \".playlist.yml\")) {\n                m_playlists.push_back(p);\n                printf(\"Found Playlist: %s\\n\", fileName.c_str());\n            } else {\n                // Not a valid file\n            }\n        } else if (p.isDirectory()) {\n            vdir child;\n            p.asDirectory(&child);\n            searchTree(child);\n        }\n    });\n}\n"
  },
  {
    "path": "SoA/MusicPlayer.h",
    "content": "///\n/// MusicPlayer.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Will play music files from a playlist\n/// TODO: Not finished yet\n///\n\n#pragma once\n\n#ifndef MusicPlayer_h__\n#define MusicPlayer_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/IO.h>\n\nclass SoaFileSystem;\nDECL_VSOUND(class Engine)\n\nclass MusicPlayer {\npublic:\n    void refreshLists(const SoaFileSystem& fs);\n\n    void begin(vsound::Engine& engine);\n    void stop();\nprivate:\n    void searchTree(const vdir& path);\n\n    bool m_isRunning = false;\n\n    std::vector<vpath> m_music;\n    std::vector<vpath> m_playlists;\n};\n\n#endif // MusicPlayer_h__\n"
  },
  {
    "path": "SoA/NightVisionRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"NightVisionRenderStage.h\"\n\n#include <ctime>\n\n#include <Vorb/colors.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/Random.h>\n#include <Vorb/graphics/SamplerState.h>\n#include <Vorb/graphics/FullQuadVBO.h>\n#include \"ShaderLoader.h\"\n\n#include \"SoaOptions.h\"\n\nKEG_TYPE_DEF_SAME_NAME(NightVisionRenderParams, kt) {\n    using namespace keg;\n    kt.addValue(\"Color\", Value::basic(offsetof(NightVisionRenderParams, color), BasicType::F32_V3));\n    kt.addValue(\"Contrast\", Value::basic(offsetof(NightVisionRenderParams, luminanceExponent), BasicType::F32));\n    kt.addValue(\"Filter\", Value::basic(offsetof(NightVisionRenderParams, luminanceTare), BasicType::F32));\n    kt.addValue(\"Brightness\", Value::basic(offsetof(NightVisionRenderParams, colorAmplification), BasicType::F32));\n    kt.addValue(\"Noise\", Value::basic(offsetof(NightVisionRenderParams, noisePower), BasicType::F32));\n    kt.addValue(\"ColorNoise\", Value::basic(offsetof(NightVisionRenderParams, noiseColor), BasicType::F32));\n}\n\nNightVisionRenderParams NightVisionRenderParams::createDefault() {\n    NightVisionRenderParams v = {};\n    v.colorAmplification = NIGHT_VISION_DEFAULT_COLOR_AMPLIFICATION;\n    v.luminanceExponent = NIGHT_VISION_DEFAULT_LUMINANCE_EXPONENT;\n    v.luminanceTare = NIGHT_VISION_DEFAULT_LUMINANCE_TARE;\n    v.noisePower = NIGHT_VISION_DEFAULT_NOISE_POWER;\n    v.noiseColor = NIGHT_VISION_DEFAULT_NOISE_COLOR;\n    v.color = NIGHT_VISION_DEFAULT_VISION_COLOR;\n    return v;\n}\n\nvoid NightVisionRenderStage::hook(vg::FullQuadVBO* quad) {\n    m_quad = quad;\n    m_texNoise.width = NIGHT_VISION_NOISE_QUALITY;\n    m_texNoise.height = NIGHT_VISION_NOISE_QUALITY;\n\n    // Generate random data\n    i32 pixCount = m_texNoise.width * m_texNoise.height;\n    ui8* data = new ui8[pixCount];\n    Random r(clock());\n    for (i32 i = 0; i < pixCount; i++) {\n        data[i] = (ui8)(r.genMT() * 255.0f);\n    }\n\n    // Build noise texture\n    glGenTextures(1, &m_texNoise.id);\n    glBindTexture(GL_TEXTURE_2D, m_texNoise.id);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_texNoise.width, m_texNoise.height, 0, GL_RED, GL_UNSIGNED_BYTE, data);\n    vg::SamplerState::POINT_WRAP.set(GL_TEXTURE_2D);\n    glBindTexture(GL_TEXTURE_2D, 0);\n    delete[] data;\n}\n\nvoid NightVisionRenderStage::setParams(const NightVisionRenderParams& params) {\n    m_program.use();\n    glUniform1f(m_program.getUniform(\"unLuminanceExponent\"), params.luminanceExponent);\n    glUniform1f(m_program.getUniform(\"unLuminanceTare\"), params.luminanceTare);\n    glUniform1f(m_program.getUniform(\"unNoisePower\"), params.noisePower);\n    glUniform1f(m_program.getUniform(\"unNoiseColor\"), params.noiseColor);\n    glUniform1f(m_program.getUniform(\"unColorAmplification\"), params.colorAmplification);\n    glUniform3f(m_program.getUniform(\"unVisionColor\"), params.color.r, params.color.g, params.color.b);\n}\n\nvoid NightVisionRenderStage::dispose(StaticLoadContext& context VORB_MAYBE_UNUSED) {\n    if (m_texNoise.id) {\n        glDeleteTextures(1, &m_texNoise.id);\n        m_texNoise.id = 0;\n    }\n}\n\nvoid NightVisionRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED /*= nullptr*/) {\n    m_et += NIGHT_VISION_DEFAULT_NOISE_TIME_STEP;\n\n    //_visionColorHSL.r = fmod(_visionColorHSL.r = 0.005f, 6.28f);\n\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, m_texNoise.id);\n\n    if (!m_program.isCreated()) {\n        m_program = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\",\n                                                             \"Shaders/PostProcessing/NightVision.frag\");\n        m_program.use();\n        glUniform1i(m_program.getUniform(\"unTexColor\"), NIGHT_VISION_TEXTURE_SLOT_COLOR);\n        glUniform1i(m_program.getUniform(\"unTexNoise\"), NIGHT_VISION_TEXTURE_SLOT_NOISE);\n        setParams(NightVisionRenderParams::createDefault());\n    } else {\n        m_program.use();\n    }\n    m_program.enableVertexAttribArrays();\n\n    glUniform1f(m_program.getUniform(\"unTime\"), m_et);\n\n    glDisable(GL_DEPTH_TEST);\n    m_quad->draw();\n    glEnable(GL_DEPTH_TEST);\n\n    m_program.disableVertexAttribArrays();\n    vg::GLProgram::unuse();\n}\n"
  },
  {
    "path": "SoA/NightVisionRenderStage.h",
    "content": "///\n/// NightVisionRenderStage.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 6 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Night vision effect\n///\n\n#pragma once\n\n#ifndef NightVisionRenderStage_h__\n#define NightVisionRenderStage_h__\n\n#define NIGHT_VISION_NOISE_QUALITY 512\n#define NIGHT_VISION_DEFAULT_NOISE_POWER 0.001f\n#define NIGHT_VISION_DEFAULT_NOISE_COLOR 0.2f\n#define NIGHT_VISION_DEFAULT_LUMINANCE_TARE 0.5f\n#define NIGHT_VISION_DEFAULT_LUMINANCE_EXPONENT 1.15f\n#define NIGHT_VISION_DEFAULT_COLOR_AMPLIFICATION 5.0f\n#define NIGHT_VISION_DEFAULT_NOISE_TIME_STEP 0.016667f\n#define NIGHT_VISION_TEXTURE_SLOT_COLOR 0\n#define NIGHT_VISION_TEXTURE_SLOT_NOISE 1\n#define NIGHT_VISION_DEFAULT_VISION_COLOR f32v3(0.1f, 0.95f, 0.2f)\n\n#include <Vorb/io/Keg.h>\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/Texture.h>\n\n#include \"IRenderStage.h\"\n\nclass NightVisionRenderParams {\npublic:\n    static NightVisionRenderParams createDefault();\n\n    f32v3 color;\n    f32 luminanceExponent;\n    f32 luminanceTare;\n    f32 colorAmplification;\n    f32 noisePower;\n    f32 noiseColor;\n};\nKEG_TYPE_DECL(NightVisionRenderParams);\n\n/// Renders a night vision post-process effect\nclass NightVisionRenderStage : public IRenderStage {\npublic:\n    void hook(vg::FullQuadVBO* quad);\n\n    void setParams(const NightVisionRenderParams& params);\n\n    /// Disposes and deletes the shader and turns off visibility\n    /// If stage does lazy init, shader will reload at next draw\n    virtual void dispose(StaticLoadContext& context) override;\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera = nullptr) override;\nprivate:\n    vg::GLProgram m_program;\n    vg::FullQuadVBO* m_quad; ///< For use in processing through data\n    vg::Texture m_texNoise; ///< A noise texture for blurry static\n    f32 m_et = 0.0f; ///< Counter for elapsed total time\n    f32v3 m_visionColorHSL = NIGHT_VISION_DEFAULT_VISION_COLOR; ///< Color of night vision\n};\n\n#endif // NightVisionRenderStage_h__\n"
  },
  {
    "path": "SoA/Noise.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Noise.h\"\n\n#include <Vorb/utils.h>\n\nKEG_TYPE_DEF_SAME_NAME(NoiseBase, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, NoiseBase, base, F64);\n    kt.addValue(\"funcs\", keg::Value::array(offsetof(NoiseBase, funcs), keg::Value::custom(0, \"TerrainFuncProperties\", false)));\n}\n\nKEG_ENUM_DEF(TerrainStage, TerrainStage, kt) {\n    kt.addValue(\"noise\", TerrainStage::NOISE);\n    kt.addValue(\"squared\", TerrainStage::SQUARED);\n    kt.addValue(\"cubed\", TerrainStage::CUBED);\n    kt.addValue(\"noise_ridged\", TerrainStage::RIDGED_NOISE);\n    kt.addValue(\"noise_abs\", TerrainStage::ABS_NOISE);\n    kt.addValue(\"noise_squared\", TerrainStage::SQUARED_NOISE);\n    kt.addValue(\"noise_cubed\", TerrainStage::CUBED_NOISE);\n    kt.addValue(\"noise_cellular\", TerrainStage::CELLULAR_NOISE);\n    kt.addValue(\"noise_cellular_squared\", TerrainStage::CELLULAR_SQUARED_NOISE);\n    kt.addValue(\"noise_cellular_cubed\", TerrainStage::CELLULAR_CUBED_NOISE);\n    kt.addValue(\"constant\", TerrainStage::CONSTANT);\n    kt.addValue(\"passthrough\", TerrainStage::PASS_THROUGH);\n}\n\nKEG_ENUM_DEF(TerrainOp, TerrainOp, kt) {\n    kt.addValue(\"add\", TerrainOp::ADD);\n    kt.addValue(\"sub\", TerrainOp::SUB);\n    kt.addValue(\"mul\", TerrainOp::MUL);\n    kt.addValue(\"div\", TerrainOp::DIV);\n}\n\nKEG_TYPE_DEF_SAME_NAME(TerrainFuncProperties, kt) {\n    kt.addValue(\"type\", keg::Value::custom(offsetof(TerrainFuncProperties, func), \"TerrainStage\", true));\n    kt.addValue(\"op\", keg::Value::custom(offsetof(TerrainFuncProperties, op), \"TerrainOp\", true));\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainFuncProperties, octaves, I32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainFuncProperties, persistence, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainFuncProperties, frequency, F64);\n    kt.addValue(\"val\", keg::Value::basic(offsetof(TerrainFuncProperties, low), keg::BasicType::F64));\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainFuncProperties, low, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainFuncProperties, high, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainFuncProperties, clamp, F64_V2);\n    kt.addValue(\"children\", keg::Value::array(offsetof(TerrainFuncProperties, children), keg::Value::custom(0, \"TerrainFuncProperties\", false)));\n}\n\n\n//\n// Description : Array and textureless 2D/3D/4D simplex \n//               noise functions.\n//      Author : Ian McEwan, Ashima Arts.\n//  Maintainer : ijm\n//     Lastmod : 20110822 (ijm)\n//     License : Copyright (C) 2011 Ashima Arts. MIT License.\n//               Distributed under the MIT License. See LICENSE file.\n//               https://github.com/ashima/webgl-noise\n// \n// Converted to C++ by Ben Arnold\n\n// Permutation polynomial: (34x^2 + x) mod 289\ninline f64v3 permute(const f64v3& x) {\n    return glm::mod((34.0 * x + 1.0) * x, 289.0);\n}\n\n\n// TODO(Ben): Fastfloor?\nf64v2 Noise::cellular(const f64v3& P) {\n#define K 0.142857142857 // 1/7\n#define Ko 0.428571428571 // 1/2-K/2\n#define K2 0.020408163265306 // 1/(7*7)\n#define Kz 0.166666666667 // 1/6\n#define Kzo 0.416666666667 // 1/2-1/6*2\n#define jitter 1.0 // smaller jitter gives more regular pattern\n\n    f64v3 Pi = glm::mod(glm::floor(P), 289.0);\n    f64v3 Pf = glm::fract(P) - 0.5;\n\n    f64v3 Pfx = Pf.x + f64v3(1.0, 0.0, -1.0);\n    f64v3 Pfy = Pf.y + f64v3(1.0, 0.0, -1.0);\n    f64v3 Pfz = Pf.z + f64v3(1.0, 0.0, -1.0);\n\n    f64v3 p = permute(Pi.x + f64v3(-1.0, 0.0, 1.0));\n    f64v3 p1 = permute(p + Pi.y - 1.0);\n    f64v3 p2 = permute(p + Pi.y);\n    f64v3 p3 = permute(p + Pi.y + 1.0);\n\n    f64v3 p11 = permute(p1 + Pi.z - 1.0);\n    f64v3 p12 = permute(p1 + Pi.z);\n    f64v3 p13 = permute(p1 + Pi.z + 1.0);\n\n    f64v3 p21 = permute(p2 + Pi.z - 1.0);\n    f64v3 p22 = permute(p2 + Pi.z);\n    f64v3 p23 = permute(p2 + Pi.z + 1.0);\n\n    f64v3 p31 = permute(p3 + Pi.z - 1.0);\n    f64v3 p32 = permute(p3 + Pi.z);\n    f64v3 p33 = permute(p3 + Pi.z + 1.0);\n\n    f64v3 ox11 = glm::fract(p11*K) - Ko;\n    f64v3 oy11 = glm::mod(glm::floor(p11*K), 7.0)*K - Ko;\n    f64v3 oz11 = glm::floor(p11*K2)*Kz - Kzo; // p11 < 289 guaranteed\n\n    f64v3 ox12 = glm::fract(p12*K) - Ko;\n    f64v3 oy12 = glm::mod(glm::floor(p12*K), 7.0)*K - Ko;\n    f64v3 oz12 = glm::floor(p12*K2)*Kz - Kzo;\n\n    f64v3 ox13 = glm::fract(p13*K) - Ko;\n    f64v3 oy13 = glm::mod(glm::floor(p13*K), 7.0)*K - Ko;\n    f64v3 oz13 = glm::floor(p13*K2)*Kz - Kzo;\n\n    f64v3 ox21 = glm::fract(p21*K) - Ko;\n    f64v3 oy21 = glm::mod(glm::floor(p21*K), 7.0)*K - Ko;\n    f64v3 oz21 = glm::floor(p21*K2)*Kz - Kzo;\n\n    f64v3 ox22 = glm::fract(p22*K) - Ko;\n    f64v3 oy22 = glm::mod(glm::floor(p22*K), 7.0)*K - Ko;\n    f64v3 oz22 = glm::floor(p22*K2)*Kz - Kzo;\n\n    f64v3 ox23 = glm::fract(p23*K) - Ko;\n    f64v3 oy23 = glm::mod(glm::floor(p23*K), 7.0)*K - Ko;\n    f64v3 oz23 = glm::floor(p23*K2)*Kz - Kzo;\n\n    f64v3 ox31 = glm::fract(p31*K) - Ko;\n    f64v3 oy31 = glm::mod(glm::floor(p31*K), 7.0)*K - Ko;\n    f64v3 oz31 = glm::floor(p31*K2)*Kz - Kzo;\n\n    f64v3 ox32 = glm::fract(p32*K) - Ko;\n    f64v3 oy32 = glm::mod(glm::floor(p32*K), 7.0)*K - Ko;\n    f64v3 oz32 = glm::floor(p32*K2)*Kz - Kzo;\n\n    f64v3 ox33 = glm::fract(p33*K) - Ko;\n    f64v3 oy33 = glm::mod(glm::floor(p33*K), 7.0)*K - Ko;\n    f64v3 oz33 = glm::floor(p33*K2)*Kz - Kzo;\n\n    f64v3 dx11 = Pfx + jitter*ox11;\n    f64v3 dy11 = Pfy.x + jitter*oy11;\n    f64v3 dz11 = Pfz.x + jitter*oz11;\n\n    f64v3 dx12 = Pfx + jitter*ox12;\n    f64v3 dy12 = Pfy.x + jitter*oy12;\n    f64v3 dz12 = Pfz.y + jitter*oz12;\n\n    f64v3 dx13 = Pfx + jitter*ox13;\n    f64v3 dy13 = Pfy.x + jitter*oy13;\n    f64v3 dz13 = Pfz.z + jitter*oz13;\n\n    f64v3 dx21 = Pfx + jitter*ox21;\n    f64v3 dy21 = Pfy.y + jitter*oy21;\n    f64v3 dz21 = Pfz.x + jitter*oz21;\n\n    f64v3 dx22 = Pfx + jitter*ox22;\n    f64v3 dy22 = Pfy.y + jitter*oy22;\n    f64v3 dz22 = Pfz.y + jitter*oz22;\n\n    f64v3 dx23 = Pfx + jitter*ox23;\n    f64v3 dy23 = Pfy.y + jitter*oy23;\n    f64v3 dz23 = Pfz.z + jitter*oz23;\n\n    f64v3 dx31 = Pfx + jitter*ox31;\n    f64v3 dy31 = Pfy.z + jitter*oy31;\n    f64v3 dz31 = Pfz.x + jitter*oz31;\n\n    f64v3 dx32 = Pfx + jitter*ox32;\n    f64v3 dy32 = Pfy.z + jitter*oy32;\n    f64v3 dz32 = Pfz.y + jitter*oz32;\n\n    f64v3 dx33 = Pfx + jitter*ox33;\n    f64v3 dy33 = Pfy.z + jitter*oy33;\n    f64v3 dz33 = Pfz.z + jitter*oz33;\n\n    f64v3 d11 = dx11 * dx11 + dy11 * dy11 + dz11 * dz11;\n    f64v3 d12 = dx12 * dx12 + dy12 * dy12 + dz12 * dz12;\n    f64v3 d13 = dx13 * dx13 + dy13 * dy13 + dz13 * dz13;\n    f64v3 d21 = dx21 * dx21 + dy21 * dy21 + dz21 * dz21;\n    f64v3 d22 = dx22 * dx22 + dy22 * dy22 + dz22 * dz22;\n    f64v3 d23 = dx23 * dx23 + dy23 * dy23 + dz23 * dz23;\n    f64v3 d31 = dx31 * dx31 + dy31 * dy31 + dz31 * dz31;\n    f64v3 d32 = dx32 * dx32 + dy32 * dy32 + dz32 * dz32;\n    f64v3 d33 = dx33 * dx33 + dy33 * dy33 + dz33 * dz33;\n\n    // Sort out the two smallest distances (F1, F2)\n#if 0\n    // Cheat and sort out only F1\n    f64v3 d1 = glm::min(glm::min(d11, d12), d13);\n    f64v3 d2 = glm::min(glm::min(d21, d22), d23);\n    f64v3 d3 = glm::min(glm::min(d31, d32), d33);\n    f64v3 d = glm::min(glm::min(d1, d2), d3);\n    d.x = glm::min(glm::min(d.x, d.y), d.z);\n    return glm::sqrt(d.xx); // F1 duplicated, no F2 computed\n#else\n    // Do it right and sort out both F1 and F2\n    f64v3 d1a = glm::min(d11, d12);\n    d12 = glm::max(d11, d12);\n    d11 = glm::min(d1a, d13); // Smallest now not in d12 or d13\n    d13 = glm::max(d1a, d13);\n    d12 = glm::min(d12, d13); // 2nd smallest now not in d13\n    f64v3 d2a = glm::min(d21, d22);\n    d22 = glm::max(d21, d22);\n    d21 = glm::min(d2a, d23); // Smallest now not in d22 or d23\n    d23 = glm::max(d2a, d23);\n    d22 = glm::min(d22, d23); // 2nd smallest now not in d23\n    f64v3 d3a = glm::min(d31, d32);\n    d32 = glm::max(d31, d32);\n    d31 = glm::min(d3a, d33); // Smallest now not in d32 or d33\n    d33 = glm::max(d3a, d33);\n    d32 = glm::min(d32, d33); // 2nd smallest now not in d33\n    f64v3 da = glm::min(d11, d21);\n    d21 = glm::max(d11, d21);\n    d11 = glm::min(da, d31); // Smallest now in d11\n    d31 = glm::max(da, d31); // 2nd smallest now not in d31\n    d11 = (d11.x < d11.y) ? d11 : f64v3(d11.y, d11.x, d11.z);\n    d11 = (d11.x < d11.z) ? d11 : f64v3(d11.z, d11.y, d11.x);\n    d12 = glm::min(d12, d21); // 2nd smallest now not in d21\n    d12 = glm::min(d12, d22); // nor in d22\n    d12 = glm::min(d12, d31); // nor in d31\n    d12 = glm::min(d12, d32); // nor in d32\n    d11 = f64v3(d11.x, glm::min(f64v2(d11.y, d11.z), f64v2(d12.x, d12.y))); // nor in d12.yz\n    d11.y = glm::min(d11.y, d12.z); // Only two more to go\n    d11.y = glm::min(d11.y, d11.z); // Done! (Phew!)\n    return glm::sqrt(f64v2(d11.x, d11.y)); // F1, F2\n#endif\n}\n\n// Multi-octave Simplex noise\n// For each octave, a higher frequency/lower amplitude function will be added to the original.\n// The higher the persistence [0-1], the more of each succeeding octave will be added.\n\n//SOURCE\n// http://www.6by9.net/simplex-noise-for-c-and-python/\n\n\n#define offsetfmult 1.45\n\ninline int fastfloor(const f64 x) { return x > 0 ? (int)x : (int)x - 1; }\n\ninline f64 dot(const f64* g, const f64 x, const f64 y) { return g[0] * x + g[1] * y; }\ninline f64 dot(const f64* g, const f64 x, const f64 y, const f64 z) { return g[0] * x + g[1] * y + g[2] * z; }\ninline f64 dot(const f64* g, const f64 x, const f64 y, const f64 z, const f64 w) { return g[0] * x + g[1] * y + g[2] * z + g[3] * w; }\n\nf64 Noise::fractal(const int octaves, const f64 persistence, const f64 freq, const f64 x, const f64 y) {\n    f64 total = 0.0;\n    f64 frequency = freq;\n    f64 amplitude = 1.0;\n\n    // We have to keep track of the largest possible amplitude,\n    // because each octave adds more, and we need a value in [-1, 1].\n    f64 maxAmplitude = 0.0;\n\n    for (int i = 0; i < octaves; i++) {\n        total += raw(x * frequency, y * frequency) * amplitude;\n\n        frequency *= 2.0;\n        maxAmplitude += amplitude;\n        amplitude *= persistence;\n    }\n\n    return total / maxAmplitude;\n}\n\nf64 Noise::fractal(const int octaves, const f64 persistence, const f64 freq, const f64 x, const f64 y, const f64 z) {\n    f64 total = 0.0;\n    f64 frequency = freq;\n    f64 amplitude = 1.0;\n\n    // We have to keep track of the largest possible amplitude,\n    // because each octave adds more, and we need a value in [-1, 1].\n    f64 maxAmplitude = 0.0;\n\n    for (int i = 0; i < octaves; i++) {\n        total += raw(x * frequency, y * frequency, z * frequency) * amplitude;\n\n        frequency *= 2.0;\n        maxAmplitude += amplitude;\n        amplitude *= persistence;\n    }\n\n    return total / maxAmplitude;\n}\n\nf64 Noise::fractal(const int octaves, const f64 persistence, const f64 freq, const f64 x, const f64 y, const f64 z, const f64 w) {\n    f64 total = 0;\n    f64 frequency = freq;\n    f64 amplitude = 1;\n\n    // We have to keep track of the largest possible amplitude,\n    // because each octave adds more, and we need a value in [-1, 1].\n    f64 maxAmplitude = 0;\n\n    for (int i = 0; i < octaves; i++) {\n        total += raw(x * frequency, y * frequency, z * frequency, w * frequency) * amplitude;\n\n        frequency *= 2.0;\n        maxAmplitude += amplitude;\n        amplitude *= persistence;\n    }\n\n    return total / maxAmplitude;\n}\n\n\n// 2D raw Simplex noise\nf64 Noise::raw(const f64 x, const f64 y) {\n    // Noise contributions from the three corners\n    f64 n0, n1, n2;\n\n    // Skew the input space to determine which simplex cell we're in\n    f64 F2 = 0.5 * (sqrtf(3.0) - 1.0);\n    // Hairy factor for 2D\n    f64 s = (x + y) * F2;\n    int i = fastFloor(x + s);\n    int j = fastFloor(y + s);\n\n    f64 G2 = (3.0 - sqrtf(3.0)) / 6.0;\n    f64 t = (i + j) * G2;\n    // Unskew the cell origin back to (x,y) space\n    f64 X0 = i - t;\n    f64 Y0 = j - t;\n    // The x,y distances from the cell origin\n    f64 x0 = x - X0;\n    f64 y0 = y - Y0;\n\n    // For the 2D case, the simplex shape is an equilateral triangle.\n    // Determine which simplex we are in.\n    int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords\n    if (x0>y0) { i1 = 1; j1 = 0; } // lower triangle, XY order: (0,0)->(1,0)->(1,1)\n    else { i1 = 0; j1 = 1; } // upper triangle, YX order: (0,0)->(0,1)->(1,1)\n\n    // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and\n    // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where\n    // c = (3-sqrt(3))/6\n    f64 x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords\n    f64 y1 = y0 - j1 + G2;\n    f64 x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords\n    f64 y2 = y0 - 1.0 + 2.0 * G2;\n\n    // Work out the hashed gradient indices of the three simplex corners\n    int ii = i & 255;\n    int jj = j & 255;\n    int gi0 = perm[ii + perm[jj]] % 12;\n    int gi1 = perm[ii + i1 + perm[jj + j1]] % 12;\n    int gi2 = perm[ii + 1 + perm[jj + 1]] % 12;\n\n    // Calculate the contribution from the three corners\n    f64 t0 = 0.5 - x0*x0 - y0*y0;\n    if (t0<0) n0 = 0.0;\n    else {\n        t0 *= t0;\n        n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient\n    }\n\n    f64 t1 = 0.5 - x1*x1 - y1*y1;\n    if (t1<0) n1 = 0.0;\n    else {\n        t1 *= t1;\n        n1 = t1 * t1 * dot(grad3[gi1], x1, y1);\n    }\n\n    f64 t2 = 0.5 - x2*x2 - y2*y2;\n    if (t2<0) n2 = 0.0;\n    else {\n        t2 *= t2;\n        n2 = t2 * t2 * dot(grad3[gi2], x2, y2);\n    }\n\n    // Add contributions from each corner to get the final noise value.\n    // The result is scaled to return values in the interval [-1,1].\n    return 70.0 * (n0 + n1 + n2);\n}\n\n// 3D raw Simplex noise\nf64 Noise::raw(const f64 x, const f64 y, const f64 z) {\n    f64 n0, n1, n2, n3; // Noise contributions from the four corners\n\n    // Skew the input space to determine which simplex cell we're in\n    const f64 F3 = 1.0 / 3.0;\n    f64 s = (x + y + z)*F3; // Very nice and simple skew factor for 3D\n    int i = fastFloor(x + s);\n    int j = fastFloor(y + s);\n    int k = fastFloor(z + s);\n\n    const f64 G3 = 1.0 / 6.0; // Very nice and simple unskew factor, too\n    f64 t = (i + j + k)*G3;\n    f64 X0 = i - t; // Unskew the cell origin back to (x,y,z) space\n    f64 Y0 = j - t;\n    f64 Z0 = k - t;\n    f64 x0 = x - X0; // The x,y,z distances from the cell origin\n    f64 y0 = y - Y0;\n    f64 z0 = z - Z0;\n\n    // For the 3D case, the simplex shape is a slightly irregular tetrahedron.\n    // Determine which simplex we are in.\n    int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords\n    int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords\n\n    if (x0 >= y0) {\n        if (y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // X Y Z order\n        else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } // X Z Y order\n        else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } // Z X Y order\n    } else { // x0<y0\n        if (y0<z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } // Z Y X order\n        else if (x0<z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } // Y Z X order\n        else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // Y X Z order\n    }\n\n    // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),\n    // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and\n    // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where\n    // c = 1/6.\n    f64 x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords\n    f64 y1 = y0 - j1 + G3;\n    f64 z1 = z0 - k1 + G3;\n    f64 x2 = x0 - i2 + 2.0*G3; // Offsets for third corner in (x,y,z) coords\n    f64 y2 = y0 - j2 + 2.0*G3;\n    f64 z2 = z0 - k2 + 2.0*G3;\n    f64 x3 = x0 - 1.0 + 3.0*G3; // Offsets for last corner in (x,y,z) coords\n    f64 y3 = y0 - 1.0 + 3.0*G3;\n    f64 z3 = z0 - 1.0 + 3.0*G3;\n\n    // Work out the hashed gradient indices of the four simplex corners\n    int ii = i & 255;\n    int jj = j & 255;\n    int kk = k & 255;\n    int gi0 = perm[ii + perm[jj + perm[kk]]] % 12;\n    int gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12;\n    int gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12;\n    int gi3 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12;\n\n    // Calculate the contribution from the four corners\n    f64 t0 = 0.6 - x0*x0 - y0*y0 - z0*z0;\n    if (t0<0) n0 = 0.0;\n    else {\n        t0 *= t0;\n        n0 = t0 * t0 * dot(grad3[gi0], x0, y0, z0);\n    }\n\n    f64 t1 = 0.6 - x1*x1 - y1*y1 - z1*z1;\n    if (t1<0) n1 = 0.0;\n    else {\n        t1 *= t1;\n        n1 = t1 * t1 * dot(grad3[gi1], x1, y1, z1);\n    }\n\n    f64 t2 = 0.6 - x2*x2 - y2*y2 - z2*z2;\n    if (t2<0) n2 = 0.0;\n    else {\n        t2 *= t2;\n        n2 = t2 * t2 * dot(grad3[gi2], x2, y2, z2);\n    }\n\n    f64 t3 = 0.6 - x3*x3 - y3*y3 - z3*z3;\n    if (t3<0) n3 = 0.0;\n    else {\n        t3 *= t3;\n        n3 = t3 * t3 * dot(grad3[gi3], x3, y3, z3);\n    }\n\n    // Add contributions from each corner to get the final noise value.\n    // The result is scaled to stay just inside [-1,1]\n    return 32.0 * (n0 + n1 + n2 + n3);\n}\n\n// 4D raw Simplex noise\nf64 Noise::raw(const f64 x, const f64 y, const f64 z, const f64 w) {\n    // The skewing and unskewing factors are hairy again for the 4D case\n    f64 F4 = (sqrtf(5.0) - 1.0) / 4.0;\n    f64 G4 = (5.0 - sqrtf(5.0)) / 20.0;\n    f64 n0, n1, n2, n3, n4; // Noise contributions from the five corners\n\n    // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in\n    f64 s = (x + y + z + w) * F4; // Factor for 4D skewing\n    int i = fastFloor(x + s);\n    int j = fastFloor(y + s);\n    int k = fastFloor(z + s);\n    int l = fastFloor(w + s);\n    f64 t = (i + j + k + l) * G4; // Factor for 4D unskewing\n    f64 X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space\n    f64 Y0 = j - t;\n    f64 Z0 = k - t;\n    f64 W0 = l - t;\n\n    f64 x0 = x - X0; // The x,y,z,w distances from the cell origin\n    f64 y0 = y - Y0;\n    f64 z0 = z - Z0;\n    f64 w0 = w - W0;\n\n    // For the 4D case, the simplex is a 4D shape I won't even try to describe.\n    // To find out which of the 24 possible simplices we're in, we need to\n    // determine the magnitude ordering of x0, y0, z0 and w0.\n    // The method below is a good way of finding the ordering of x,y,z,w and\n    // then find the correct traversal order for the simplex we're in.\n    // First, six pair-wise comparisons are performed between each possible pair\n    // of the four coordinates, and the results are used to add up binary bits\n    // for an integer index.\n    int c1 = (x0 > y0) ? 32 : 0;\n    int c2 = (x0 > z0) ? 16 : 0;\n    int c3 = (y0 > z0) ? 8 : 0;\n    int c4 = (x0 > w0) ? 4 : 0;\n    int c5 = (y0 > w0) ? 2 : 0;\n    int c6 = (z0 > w0) ? 1 : 0;\n    int c = c1 + c2 + c3 + c4 + c5 + c6;\n\n    int i1, j1, k1, l1; // The integer offsets for the second simplex corner\n    int i2, j2, k2, l2; // The integer offsets for the third simplex corner\n    int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner\n\n    // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.\n    // Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w\n    // impossible. Only the 24 indices which have non-zero entries make any sense.\n    // We use a thresholding to set the coordinates in turn from the largest magnitude.\n    // The number 3 in the \"simplex\" array is at the position of the largest coordinate.\n    i1 = simplex[c][0] >= 3 ? 1 : 0;\n    j1 = simplex[c][1] >= 3 ? 1 : 0;\n    k1 = simplex[c][2] >= 3 ? 1 : 0;\n    l1 = simplex[c][3] >= 3 ? 1 : 0;\n    // The number 2 in the \"simplex\" array is at the second largest coordinate.\n    i2 = simplex[c][0] >= 2 ? 1 : 0;\n    j2 = simplex[c][1] >= 2 ? 1 : 0;\n    k2 = simplex[c][2] >= 2 ? 1 : 0;\n    l2 = simplex[c][3] >= 2 ? 1 : 0;\n    // The number 1 in the \"simplex\" array is at the second smallest coordinate.\n    i3 = simplex[c][0] >= 1 ? 1 : 0;\n    j3 = simplex[c][1] >= 1 ? 1 : 0;\n    k3 = simplex[c][2] >= 1 ? 1 : 0;\n    l3 = simplex[c][3] >= 1 ? 1 : 0;\n    // The fifth corner has all coordinate offsets = 1, so no need to look that up.\n\n    f64 x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords\n    f64 y1 = y0 - j1 + G4;\n    f64 z1 = z0 - k1 + G4;\n    f64 w1 = w0 - l1 + G4;\n    f64 x2 = x0 - i2 + 2.0*G4; // Offsets for third corner in (x,y,z,w) coords\n    f64 y2 = y0 - j2 + 2.0*G4;\n    f64 z2 = z0 - k2 + 2.0*G4;\n    f64 w2 = w0 - l2 + 2.0*G4;\n    f64 x3 = x0 - i3 + 3.0*G4; // Offsets for fourth corner in (x,y,z,w) coords\n    f64 y3 = y0 - j3 + 3.0*G4;\n    f64 z3 = z0 - k3 + 3.0*G4;\n    f64 w3 = w0 - l3 + 3.0*G4;\n    f64 x4 = x0 - 1.0 + 4.0*G4; // Offsets for last corner in (x,y,z,w) coords\n    f64 y4 = y0 - 1.0 + 4.0*G4;\n    f64 z4 = z0 - 1.0 + 4.0*G4;\n    f64 w4 = w0 - 1.0 + 4.0*G4;\n\n    // Work out the hashed gradient indices of the five simplex corners\n    int ii = i & 255;\n    int jj = j & 255;\n    int kk = k & 255;\n    int ll = l & 255;\n    int gi0 = perm[ii + perm[jj + perm[kk + perm[ll]]]] % 32;\n    int gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]] % 32;\n    int gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]] % 32;\n    int gi3 = perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]] % 32;\n    int gi4 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]] % 32;\n\n    // Calculate the contribution from the five corners\n    f64 t0 = 0.6 - x0*x0 - y0*y0 - z0*z0 - w0*w0;\n    if (t0<0) n0 = 0.0;\n    else {\n        t0 *= t0;\n        n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);\n    }\n\n    f64 t1 = 0.6 - x1*x1 - y1*y1 - z1*z1 - w1*w1;\n    if (t1<0) n1 = 0.0;\n    else {\n        t1 *= t1;\n        n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);\n    }\n\n    f64 t2 = 0.6 - x2*x2 - y2*y2 - z2*z2 - w2*w2;\n    if (t2<0) n2 = 0.0;\n    else {\n        t2 *= t2;\n        n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);\n    }\n\n    f64 t3 = 0.6 - x3*x3 - y3*y3 - z3*z3 - w3*w3;\n    if (t3<0) n3 = 0.0;\n    else {\n        t3 *= t3;\n        n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);\n    }\n\n    f64 t4 = 0.6 - x4*x4 - y4*y4 - z4*z4 - w4*w4;\n    if (t4<0) n4 = 0.0;\n    else {\n        t4 *= t4;\n        n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);\n    }\n\n    // Sum up and scale the result to cover the range [-1,1]\n    return 27.0 * (n0 + n1 + n2 + n3 + n4);\n}\n"
  },
  {
    "path": "SoA/Noise.h",
    "content": "///\n/// Noise.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Jul 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// \n///\n\n#pragma once\n\n#ifndef Noise_h__\n#define Noise_h__\n\n#include <Vorb/io/Keg.h>\n\nenum class TerrainStage {\n    NOISE,\n    SQUARED,\n    CUBED,\n    RIDGED_NOISE,\n    ABS_NOISE,\n    SQUARED_NOISE,\n    CUBED_NOISE,\n    CELLULAR_NOISE,\n    CELLULAR_SQUARED_NOISE,\n    CELLULAR_CUBED_NOISE,\n    CONSTANT,\n    PASS_THROUGH\n};\nKEG_ENUM_DECL(TerrainStage);\n\nenum class TerrainOp {\n    ADD = 0,\n    SUB,\n    MUL,\n    DIV\n};\nKEG_ENUM_DECL(TerrainOp);\n\nstruct TerrainFuncProperties {\n    TerrainStage func = TerrainStage::NOISE;\n    TerrainOp op = TerrainOp::ADD;\n    int octaves = 1;\n    f64 persistence = 1.0;\n    f64 frequency = 1.0;\n    f64 low = -1.0;\n    f64 high = 1.0;\n    f64v2 clamp = f64v2(0.0);\n    Array<TerrainFuncProperties> children;\n};\nKEG_TYPE_DECL(TerrainFuncProperties);\n\nstruct NoiseBase {\n    f64 base = 0.0f;\n    Array<TerrainFuncProperties> funcs;\n};\nKEG_TYPE_DECL(NoiseBase);\n\nnamespace Noise {\n    f64v2 cellular(const f64v3& P);\n\n    // Mulit-octave simplex noise\n    f64 fractal(const int octaves,\n                const f64 persistence,\n                const f64 freq,\n                const f64 x,\n                const f64 y);\n    f64 fractal(const int octaves,\n                const f64 persistence,\n                const f64 freq,\n                const f64 x,\n                const f64 y,\n                const f64 z);\n    f64 fractal(const int octaves,\n                const f64 persistence,\n                const f64 freq,\n                const f64 x,\n                const f64 y,\n                const f64 z,\n                const f64 w);\n\n    // Raw Simplex noise - a single noise value.\n    f64 raw(const f64 x, const f64 y);\n    f64 raw(const f64 x, const f64 y, const f64 z);\n    f64 raw(const f64 x, const f64 y, const f64, const f64 w);\n\n    // Scaled Multi-octave Simplex noise\n    // The result will be between the two parameters passed.\n    inline f64 scaledFractal(const int octaves, const f64 persistence, const f64 freq, const f64 loBound, const f64 hiBound, const f64 x, const f64 y) {\n        return fractal(octaves, persistence, freq, x, y) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2;\n    }\n    inline f64 scaledFractal(const int octaves, const f64 persistence, const f64 freq, const f64 loBound, const f64 hiBound, const f64 x, const f64 y, const f64 z) {\n        return fractal(octaves, persistence, freq, x, y, z) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2;\n    }\n    inline f64 scaledFractal(const int octaves, const f64 persistence, const f64 freq, const f64 loBound, const f64 hiBound, const f64 x, const f64 y, const f64 z, const f64 w) {\n        return fractal(octaves, persistence, freq, x, y, z, w) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2;\n    }\n\n    // Scaled Raw Simplex noise\n    // The result will be between the two parameters passed.\n    inline f64 scaledRaw(const f64 loBound, const f64 hiBound, const f64 x, const f64 y) {\n        return raw(x, y) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2;\n    }\n    inline f64 scaledRaw(const f64 loBound, const f64 hiBound, const f64 x, const f64 y, const f64 z) {\n        return raw(x, y, z) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2;\n    }\n    inline f64 scaledRaw(const f64 loBound, const f64 hiBound, const f64 x, const f64 y, const f64 z, const f64 w) {\n        return raw(x, y, z, w) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2;\n    }\n\n    // The gradients are the midpoints of the vertices of a cube.\n    const f64 grad3[12][3] = {\n        { 1, 1, 0 }, { -1, 1, 0 }, { 1, -1, 0 }, { -1, -1, 0 },\n        { 1, 0, 1 }, { -1, 0, 1 }, { 1, 0, -1 }, { -1, 0, -1 },\n        { 0, 1, 1 }, { 0, -1, 1 }, { 0, 1, -1 }, { 0, -1, -1 }\n    };\n\n    // The gradients are the midpoints of the vertices of a hypercube.\n    const f64 grad4[32][4] = {\n        { 0, 1, 1, 1 }, { 0, 1, 1, -1 }, { 0, 1, -1, 1 }, { 0, 1, -1, -1 },\n        { 0, -1, 1, 1 }, { 0, -1, 1, -1 }, { 0, -1, -1, 1 }, { 0, -1, -1, -1 },\n        { 1, 0, 1, 1 }, { 1, 0, 1, -1 }, { 1, 0, -1, 1 }, { 1, 0, -1, -1 },\n        { -1, 0, 1, 1 }, { -1, 0, 1, -1 }, { -1, 0, -1, 1 }, { -1, 0, -1, -1 },\n        { 1, 1, 0, 1 }, { 1, 1, 0, -1 }, { 1, -1, 0, 1 }, { 1, -1, 0, -1 },\n        { -1, 1, 0, 1 }, { -1, 1, 0, -1 }, { -1, -1, 0, 1 }, { -1, -1, 0, -1 },\n        { 1, 1, 1, 0 }, { 1, 1, -1, 0 }, { 1, -1, 1, 0 }, { 1, -1, -1, 0 },\n        { -1, 1, 1, 0 }, { -1, 1, -1, 0 }, { -1, -1, 1, 0 }, { -1, -1, -1, 0 }\n    };\n\n\n    // Permutation table.  The same list is repeated twice.\n    const int perm[512] = {\n        151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142,\n        8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117,\n        35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71,\n        134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41,\n        55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89,\n        18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226,\n        250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182,\n        189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43,\n        172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97,\n        228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239,\n        107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254,\n        138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,\n\n        151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142,\n        8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117,\n        35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71,\n        134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41,\n        55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89,\n        18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226,\n        250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182,\n        189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43,\n        172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97,\n        228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239,\n        107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254,\n        138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180\n    };\n\n\n    // A lookup table to traverse the simplex around a given point in 4D.\n    const int simplex[64][4] = {\n        { 0, 1, 2, 3 }, { 0, 1, 3, 2 }, { 0, 0, 0, 0 }, { 0, 2, 3, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 2, 3, 0 },\n        { 0, 2, 1, 3 }, { 0, 0, 0, 0 }, { 0, 3, 1, 2 }, { 0, 3, 2, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 3, 2, 0 },\n        { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },\n        { 1, 2, 0, 3 }, { 0, 0, 0, 0 }, { 1, 3, 0, 2 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 2, 3, 0, 1 }, { 2, 3, 1, 0 },\n        { 1, 0, 2, 3 }, { 1, 0, 3, 2 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 2, 0, 3, 1 }, { 0, 0, 0, 0 }, { 2, 1, 3, 0 },\n        { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },\n        { 2, 0, 1, 3 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 3, 0, 1, 2 }, { 3, 0, 2, 1 }, { 0, 0, 0, 0 }, { 3, 1, 2, 0 },\n        { 2, 1, 0, 3 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 3, 1, 0, 2 }, { 0, 0, 0, 0 }, { 3, 2, 0, 1 }, { 3, 2, 1, 0 }\n    };\n}\n\n#endif // Noise_h__"
  },
  {
    "path": "SoA/Octree.cpp",
    "content": "/*\nImplementations of Octree member functions.\nCopyright (C) 2011  Tao Ju\nThis library is free software; you can redistribute it and/or\nmodify it under the terms of the GNU Lesser General Public License\n(LGPL) as published by the Free Software Foundation; either\nversion 2.1 of the License, or (at your option) any later version.\nThis library is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nLesser General Public License for more details.\nYou should have received a copy of the GNU Lesser General Public\nLicense along with this library; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n*/\n#include \"stdafx.h\"\n#include \"Octree.h\"\n#include \"Density.h\"\n\n// ----------------------------------------------------------------------------\n\nconst int MATERIAL_AIR = 0;\nconst int MATERIAL_SOLID = 1;\n\nconst float QEF_ERROR = 1e-6f;\nconst int QEF_SWEEPS = 4;\n\n// ----------------------------------------------------------------------------\n\nconst i32v3 CHILD_MIN_OFFSETS[] =\n{\n    // needs to match the vertMap from Dual Contouring impl\n    i32v3(0, 0, 0),\n    i32v3(0, 0, 1),\n    i32v3(0, 1, 0),\n    i32v3(0, 1, 1),\n    i32v3(1, 0, 0),\n    i32v3(1, 0, 1),\n    i32v3(1, 1, 0),\n    i32v3(1, 1, 1),\n};\n\n// ----------------------------------------------------------------------------\n// data from the original DC impl, drives the contouring process\n\nconst int edgevmap[12][2] =\n{\n    { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 },\t// x-axis \n    { 0, 2 }, { 1, 3 }, { 4, 6 }, { 5, 7 },\t// y-axis\n    { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }\t\t// z-axis\n};\n\n// TODO: These weren't being used, why?\n\n// const int edgemask[3] = { 5, 3, 6 };\n\n// const int vertMap[8][3] =\n// {\n//     { 0, 0, 0 },\n//     { 0, 0, 1 },\n//     { 0, 1, 0 },\n//     { 0, 1, 1 },\n//     { 1, 0, 0 },\n//     { 1, 0, 1 },\n//     { 1, 1, 0 },\n//     { 1, 1, 1 }\n// };\n\n// const int faceMap[6][4] = { { 4, 8, 5, 9 }, { 6, 10, 7, 11 }, { 0, 8, 1, 10 }, { 2, 9, 3, 11 }, { 0, 4, 2, 6 }, { 1, 5, 3, 7 } };\nconst int cellProcFaceMask[12][3] = { { 0, 4, 0 }, { 1, 5, 0 }, { 2, 6, 0 }, { 3, 7, 0 }, { 0, 2, 1 }, { 4, 6, 1 }, { 1, 3, 1 }, { 5, 7, 1 }, { 0, 1, 2 }, { 2, 3, 2 }, { 4, 5, 2 }, { 6, 7, 2 } };\nconst int cellProcEdgeMask[6][5] = { { 0, 1, 2, 3, 0 }, { 4, 5, 6, 7, 0 }, { 0, 4, 1, 5, 1 }, { 2, 6, 3, 7, 1 }, { 0, 2, 4, 6, 2 }, { 1, 3, 5, 7, 2 } };\n\nconst int faceProcFaceMask[3][4][3] = {\n    { { 4, 0, 0 }, { 5, 1, 0 }, { 6, 2, 0 }, { 7, 3, 0 } },\n    { { 2, 0, 1 }, { 6, 4, 1 }, { 3, 1, 1 }, { 7, 5, 1 } },\n    { { 1, 0, 2 }, { 3, 2, 2 }, { 5, 4, 2 }, { 7, 6, 2 } }\n};\n\nconst int faceProcEdgeMask[3][4][6] = {\n    { { 1, 4, 0, 5, 1, 1 }, { 1, 6, 2, 7, 3, 1 }, { 0, 4, 6, 0, 2, 2 }, { 0, 5, 7, 1, 3, 2 } },\n    { { 0, 2, 3, 0, 1, 0 }, { 0, 6, 7, 4, 5, 0 }, { 1, 2, 0, 6, 4, 2 }, { 1, 3, 1, 7, 5, 2 } },\n    { { 1, 1, 0, 3, 2, 0 }, { 1, 5, 4, 7, 6, 0 }, { 0, 1, 5, 0, 4, 1 }, { 0, 3, 7, 2, 6, 1 } }\n};\n\nconst int edgeProcEdgeMask[3][2][5] = {\n    { { 3, 2, 1, 0, 0 }, { 7, 6, 5, 4, 0 } },\n    { { 5, 1, 4, 0, 1 }, { 7, 3, 6, 2, 1 } },\n    { { 6, 4, 2, 0, 2 }, { 7, 5, 3, 1, 2 } },\n};\n\nconst int processEdgeMask[3][4] = { { 3, 2, 1, 0 }, { 7, 5, 6, 4 }, { 11, 10, 9, 8 } };\n\n// -------------------------------------------------------------------------------\n\nOctreeNode* SimplifyOctree(OctreeNode* node, float threshold) {\n    if (!node) {\n        return NULL;\n    }\n\n    if (node->type != Node_Internal) {\n        // can't simplify!\n        return node;\n    }\n\n    svd::QefSolver qef;\n    int signs[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };\n    int midsign = -1;\n    int edgeCount = 0;\n    bool isCollapsible = true;\n\n    for (int i = 0; i < 8; i++) {\n        node->children[i] = SimplifyOctree(node->children[i], threshold);\n        if (node->children[i]) {\n            OctreeNode* child = node->children[i];\n            if (child->type == Node_Internal) {\n                isCollapsible = false;\n            } else {\n                qef.add(child->drawInfo->qef);\n\n                midsign = (child->drawInfo->corners >> (7 - i)) & 1;\n                signs[i] = (child->drawInfo->corners >> i) & 1;\n\n                edgeCount++;\n            }\n        }\n    }\n\n    if (!isCollapsible) {\n        // at least one child is an internal node, can't collapse\n        return node;\n    }\n\n    svd::Vec3 qefPosition;\n    qef.solve(qefPosition, QEF_ERROR, QEF_SWEEPS, QEF_ERROR);\n    float error = qef.getError();\n\n    // convert to glm vec3 for ease of use\n    f32v3 position(qefPosition.x, qefPosition.y, qefPosition.z);\n\n    // at this point the masspoint will actually be a sum, so divide to make it the average\n    if (error > threshold) {\n        // this collapse breaches the threshold\n        return node;\n    }\n\n    if (position.x < node->min.x || position.x >(node->min.x + node->size) ||\n        position.y < node->min.y || position.y >(node->min.y + node->size) ||\n        position.z < node->min.z || position.z >(node->min.z + node->size)) {\n        const auto& mp = qef.getMassPoint();\n        position = f32v3(mp.x, mp.y, mp.z);\n    }\n\n    // change the node from an internal node to a 'psuedo leaf' node\n    OctreeDrawInfo* drawInfo = new OctreeDrawInfo;\n\n    for (int i = 0; i < 8; i++) {\n        if (signs[i] == -1) {\n            // Undetermined, use centre sign instead\n            drawInfo->corners |= (midsign << i);\n        } else {\n            drawInfo->corners |= (signs[i] << i);\n        }\n    }\n\n    drawInfo->averageNormal = f32v3(0.f);\n    for (int i = 0; i < 8; i++) {\n        if (node->children[i]) {\n            OctreeNode* child = node->children[i];\n            if (child->type == Node_Psuedo ||\n                child->type == Node_Leaf) {\n                drawInfo->averageNormal += child->drawInfo->averageNormal;\n            }\n        }\n    }\n\n    drawInfo->averageNormal = glm::normalize(drawInfo->averageNormal);\n    drawInfo->position = position;\n    drawInfo->qef = qef.getData();\n\n    for (int i = 0; i < 8; i++) {\n        DestroyOctree(node->children[i]);\n        node->children[i] = nullptr;\n    }\n\n    node->type = Node_Psuedo;\n    node->drawInfo = drawInfo;\n\n    return node;\n}\n\n// ----------------------------------------------------------------------------\n\nvoid GenerateVertexIndices(OctreeNode* node, std::vector<VoxelModelVertex>& vertexBuffer) {\n    if (!node) {\n        return;\n    }\n\n    if (node->type != Node_Leaf) {\n        for (int i = 0; i < 8; i++) {\n            GenerateVertexIndices(node->children[i], vertexBuffer);\n        }\n    }\n\n    if (node->type != Node_Internal) {\n        OctreeDrawInfo* d = node->drawInfo;\n        if (!d) {\n            printf(\"Error! Could not add vertex!\\n\");\n            exit(EXIT_FAILURE);\n        }\n\n        d->index = vertexBuffer.size();\n        vertexBuffer.push_back(VoxelModelVertex(d->position, color3(255, 255, 255), d->averageNormal));\n    }\n}\n\n// ----------------------------------------------------------------------------\n\nvoid ContourProcessEdge(OctreeNode* node[4], int dir, std::vector<ui32>& indexBuffer) {\n    int minSize = 1000000;\t\t// arbitrary big number\n    int minIndex = 0;\n    int indices[4] = { -1, -1, -1, -1 };\n    bool flip = false;\n    bool signChange[4] = { false, false, false, false };\n\n    for (int i = 0; i < 4; i++) {\n        const int edge = processEdgeMask[dir][i];\n        const int c1 = edgevmap[edge][0];\n        const int c2 = edgevmap[edge][1];\n\n        const int m1 = (node[i]->drawInfo->corners >> c1) & 1;\n        const int m2 = (node[i]->drawInfo->corners >> c2) & 1;\n\n        if (node[i]->size < minSize) {\n            minSize = node[i]->size;\n            minIndex = i;\n            flip = m1 != MATERIAL_AIR;\n        }\n\n        indices[i] = node[i]->drawInfo->index;\n\n        signChange[i] =\n            (m1 == MATERIAL_AIR && m2 != MATERIAL_AIR) ||\n            (m1 != MATERIAL_AIR && m2 == MATERIAL_AIR);\n    }\n\n    if (signChange[minIndex]) {\n        if (!flip) {\n            indexBuffer.push_back(indices[0]);\n            indexBuffer.push_back(indices[1]);\n            indexBuffer.push_back(indices[3]);\n\n            indexBuffer.push_back(indices[0]);\n            indexBuffer.push_back(indices[3]);\n            indexBuffer.push_back(indices[2]);\n        } else {\n            indexBuffer.push_back(indices[0]);\n            indexBuffer.push_back(indices[3]);\n            indexBuffer.push_back(indices[1]);\n\n            indexBuffer.push_back(indices[0]);\n            indexBuffer.push_back(indices[2]);\n            indexBuffer.push_back(indices[3]);\n        }\n    }\n}\n\n// ----------------------------------------------------------------------------\n\nvoid ContourEdgeProc(OctreeNode* node[4], int dir, std::vector<ui32>& indexBuffer) {\n    if (!node[0] || !node[1] || !node[2] || !node[3]) {\n        return;\n    }\n\n    if (node[0]->type != Node_Internal &&\n        node[1]->type != Node_Internal &&\n        node[2]->type != Node_Internal &&\n        node[3]->type != Node_Internal) {\n        ContourProcessEdge(node, dir, indexBuffer);\n    } else {\n        for (int i = 0; i < 2; i++) {\n            OctreeNode* edgeNodes[4];\n            const int c[4] =\n            {\n                edgeProcEdgeMask[dir][i][0],\n                edgeProcEdgeMask[dir][i][1],\n                edgeProcEdgeMask[dir][i][2],\n                edgeProcEdgeMask[dir][i][3],\n            };\n\n            for (int j = 0; j < 4; j++) {\n                if (node[j]->type == Node_Leaf || node[j]->type == Node_Psuedo) {\n                    edgeNodes[j] = node[j];\n                } else {\n                    edgeNodes[j] = node[j]->children[c[j]];\n                }\n            }\n\n            ContourEdgeProc(edgeNodes, edgeProcEdgeMask[dir][i][4], indexBuffer);\n        }\n    }\n}\n\n// ----------------------------------------------------------------------------\n\nvoid ContourFaceProc(OctreeNode* node[2], int dir, std::vector<ui32>& indexBuffer) {\n    if (!node[0] || !node[1]) {\n        return;\n    }\n\n    if (node[0]->type == Node_Internal ||\n        node[1]->type == Node_Internal) {\n        for (int i = 0; i < 4; i++) {\n            OctreeNode* faceNodes[2];\n            const int c[2] =\n            {\n                faceProcFaceMask[dir][i][0],\n                faceProcFaceMask[dir][i][1],\n            };\n\n            for (int j = 0; j < 2; j++) {\n                if (node[j]->type != Node_Internal) {\n                    faceNodes[j] = node[j];\n                } else {\n                    faceNodes[j] = node[j]->children[c[j]];\n                }\n            }\n\n            ContourFaceProc(faceNodes, faceProcFaceMask[dir][i][2], indexBuffer);\n        }\n\n        const int orders[2][4] =\n        {\n            { 0, 0, 1, 1 },\n            { 0, 1, 0, 1 },\n        };\n        for (int i = 0; i < 4; i++) {\n            OctreeNode* edgeNodes[4];\n            const int c[4] =\n            {\n                faceProcEdgeMask[dir][i][1],\n                faceProcEdgeMask[dir][i][2],\n                faceProcEdgeMask[dir][i][3],\n                faceProcEdgeMask[dir][i][4],\n            };\n\n            const int* order = orders[faceProcEdgeMask[dir][i][0]];\n            for (int j = 0; j < 4; j++) {\n                if (node[order[j]]->type == Node_Leaf ||\n                    node[order[j]]->type == Node_Psuedo) {\n                    edgeNodes[j] = node[order[j]];\n                } else {\n                    edgeNodes[j] = node[order[j]]->children[c[j]];\n                }\n            }\n\n            ContourEdgeProc(edgeNodes, faceProcEdgeMask[dir][i][5], indexBuffer);\n        }\n    }\n}\n\n// ----------------------------------------------------------------------------\n\nvoid ContourCellProc(OctreeNode* node, std::vector<ui32>& indexBuffer) {\n    if (node == NULL) {\n        return;\n    }\n\n    if (node->type == Node_Internal) {\n        for (int i = 0; i < 8; i++) {\n            ContourCellProc(node->children[i], indexBuffer);\n        }\n\n        for (int i = 0; i < 12; i++) {\n            OctreeNode* faceNodes[2];\n            const int c[2] = { cellProcFaceMask[i][0], cellProcFaceMask[i][1] };\n\n            faceNodes[0] = node->children[c[0]];\n            faceNodes[1] = node->children[c[1]];\n\n            ContourFaceProc(faceNodes, cellProcFaceMask[i][2], indexBuffer);\n        }\n\n        for (int i = 0; i < 6; i++) {\n            OctreeNode* edgeNodes[4];\n            const int c[4] =\n            {\n                cellProcEdgeMask[i][0],\n                cellProcEdgeMask[i][1],\n                cellProcEdgeMask[i][2],\n                cellProcEdgeMask[i][3],\n            };\n\n            for (int j = 0; j < 4; j++) {\n                edgeNodes[j] = node->children[c[j]];\n            }\n\n            ContourEdgeProc(edgeNodes, cellProcEdgeMask[i][4], indexBuffer);\n        }\n    }\n}\n\n// ----------------------------------------------------------------------------\n\nf32v3 ApproximateZeroCrossingPosition(const f32v3& p0, const f32v3& p1) {\n    // approximate the zero crossing by finding the min value along the edge\n    float minValue = 100000.f;\n    float t = 0.f;\n    float currentT = 0.f;\n    const int steps = 8;\n    const float increment = 1.f / (float)steps;\n    while (currentT <= 1.f) {\n        const f32v3 p = p0 + ((p1 - p0) * currentT);\n        const float density = glm::abs(Density_Func(p));\n        if (density < minValue) {\n            minValue = density;\n            t = currentT;\n        }\n\n        currentT += increment;\n    }\n\n    return p0 + ((p1 - p0) * t);\n}\n\n// ----------------------------------------------------------------------------\n\nf32v3 CalculateSurfaceNormal(const f32v3& p) {\n    const float H = 0.001f;\n    const float dx = Density_Func(p + f32v3(H, 0.f, 0.f)) - Density_Func(p - f32v3(H, 0.f, 0.f));\n    const float dy = Density_Func(p + f32v3(0.f, H, 0.f)) - Density_Func(p - f32v3(0.f, H, 0.f));\n    const float dz = Density_Func(p + f32v3(0.f, 0.f, H)) - Density_Func(p - f32v3(0.f, 0.f, H));\n\n    return glm::normalize(f32v3(dx, dy, dz));\n}\n\n// ----------------------------------------------------------------------------\n\nOctreeNode* ConstructLeaf(OctreeNode* leaf) {\n    if (!leaf || leaf->size != 1) {\n        return nullptr;\n    }\n\n    int corners = 0;\n    for (int i = 0; i < 8; i++) {\n        const i32v3 cornerPos = leaf->min + CHILD_MIN_OFFSETS[i];\n        const float density = Density_Func(f32v3(cornerPos));\n        const int material = density < 0.f ? MATERIAL_SOLID : MATERIAL_AIR;\n        corners |= (material << i);\n    }\n\n    if (corners == 0 || corners == 255) {\n        // voxel is full inside or outside the volume\n        delete leaf;\n        return nullptr;\n    }\n\n    // otherwise the voxel contains the surface, so find the edge intersections\n    const int MAX_CROSSINGS = 6;\n    int edgeCount = 0;\n    f32v3 averageNormal(0.f);\n    svd::QefSolver qef;\n\n    for (int i = 0; i < 12 && edgeCount < MAX_CROSSINGS; i++) {\n        const int c1 = edgevmap[i][0];\n        const int c2 = edgevmap[i][1];\n\n        const int m1 = (corners >> c1) & 1;\n        const int m2 = (corners >> c2) & 1;\n\n        if ((m1 == MATERIAL_AIR && m2 == MATERIAL_AIR) ||\n            (m1 == MATERIAL_SOLID && m2 == MATERIAL_SOLID)) {\n            // no zero crossing on this edge\n            continue;\n        }\n\n        const f32v3 p1 = f32v3(leaf->min + CHILD_MIN_OFFSETS[c1]);\n        const f32v3 p2 = f32v3(leaf->min + CHILD_MIN_OFFSETS[c2]);\n        const f32v3 p = ApproximateZeroCrossingPosition(p1, p2);\n        const f32v3 n = CalculateSurfaceNormal(p);\n        qef.add(p.x, p.y, p.z, n.x, n.y, n.z);\n\n        averageNormal += n;\n\n        edgeCount++;\n    }\n\n    svd::Vec3 qefPosition;\n    qef.solve(qefPosition, QEF_ERROR, QEF_SWEEPS, QEF_ERROR);\n\n    OctreeDrawInfo* drawInfo = new OctreeDrawInfo;\n    drawInfo->position = f32v3(qefPosition.x, qefPosition.y, qefPosition.z);\n    drawInfo->qef = qef.getData();\n\n    const f32v3 min = f32v3(leaf->min);\n    const f32v3 max = f32v3(leaf->min + i32v3(leaf->size));\n    if (drawInfo->position.x < min.x || drawInfo->position.x > max.x ||\n        drawInfo->position.y < min.y || drawInfo->position.y > max.y ||\n        drawInfo->position.z < min.z || drawInfo->position.z > max.z) {\n        const auto& mp = qef.getMassPoint();\n        drawInfo->position = f32v3(mp.x, mp.y, mp.z);\n    }\n\n    drawInfo->averageNormal = glm::normalize(averageNormal / (float)edgeCount);\n    drawInfo->corners = corners;\n\n    leaf->type = Node_Leaf;\n    leaf->drawInfo = drawInfo;\n\n    return leaf;\n}\n\n// -------------------------------------------------------------------------------\n\nOctreeNode* ConstructOctreeNodes(OctreeNode* node) {\n    if (!node) {\n        return nullptr;\n    }\n\n    if (node->size == 1) {\n        return ConstructLeaf(node);\n    }\n\n    const int childSize = node->size / 2;\n    bool hasChildren = false;\n\n    for (int i = 0; i < 8; i++) {\n        OctreeNode* child = new OctreeNode;\n        child->size = childSize;\n        child->min = node->min + (CHILD_MIN_OFFSETS[i] * childSize);\n        child->type = Node_Internal;\n\n        node->children[i] = ConstructOctreeNodes(child);\n        hasChildren |= (node->children[i] != nullptr);\n    }\n\n    if (!hasChildren) {\n        delete node;\n        return nullptr;\n    }\n\n    return node;\n}\n\n// -------------------------------------------------------------------------------\n\nOctreeNode* BuildOctree(const i32v3& min, const int size, const float threshold) {\n    OctreeNode* root = new OctreeNode;\n    root->min = min;\n    root->size = size;\n    root->type = Node_Internal;\n\n    ConstructOctreeNodes(root);\n    root = SimplifyOctree(root, threshold);\n\n    return root;\n}\n\n// ----------------------------------------------------------------------------\n\nvoid GenerateMeshFromOctree(OctreeNode* node, std::vector<VoxelModelVertex>& vertexBuffer, std::vector<ui32>& indexBuffer) {\n    if (!node) {\n        return;\n    }\n\n    vertexBuffer.clear();\n    indexBuffer.clear();\n\n    GenerateVertexIndices(node, vertexBuffer);\n    ContourCellProc(node, indexBuffer);\n}\n\n// -------------------------------------------------------------------------------\n\nvoid DestroyOctree(OctreeNode* node) {\n    if (!node) {\n        return;\n    }\n\n    for (int i = 0; i < 8; i++) {\n        DestroyOctree(node->children[i]);\n    }\n\n    if (node->drawInfo) {\n        delete node->drawInfo;\n    }\n\n    delete node;\n}\n"
  },
  {
    "path": "SoA/Octree.h",
    "content": "/*\nImplementations of Octree member functions.\nCopyright (C) 2011  Tao Ju\nThis library is free software; you can redistribute it and/or\nmodify it under the terms of the GNU Lesser General Public License\n(LGPL) as published by the Free Software Foundation; either\nversion 2.1 of the License, or (at your option) any later version.\nThis library is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nLesser General Public License for more details.\nYou should have received a copy of the GNU Lesser General Public\nLicense along with this library; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n*/\n\n\n#ifndef\t\tHAS_OCTREE_H_BEEN_INCLUDED\n#define\t\tHAS_OCTREE_H_BEEN_INCLUDED\n\n#include \"qef.h\"\n#include \"VoxelModelMesh.h\"\n\n// ----------------------------------------------------------------------------\n\nenum OctreeNodeType {\n    Node_None,\n    Node_Internal,\n    Node_Psuedo,\n    Node_Leaf,\n};\n\n// ----------------------------------------------------------------------------\n\nstruct OctreeDrawInfo {\n    OctreeDrawInfo()\n        : index(-1)\n        , corners(0) {\n    }\n\n    int\t\t\t\tindex;\n    int\t\t\t\tcorners;\n    f32v3\t\t\tposition;\n    f32v3\t\t\taverageNormal;\n    svd::QefData\tqef;\n};\n\n// ----------------------------------------------------------------------------\n\nclass OctreeNode {\npublic:\n\n    OctreeNode()\n        : type(Node_None)\n        , min(0, 0, 0)\n        , size(0)\n        , drawInfo(nullptr) {\n        memset(children, 0, sizeof(children));\n    }\n\n    OctreeNode(const OctreeNodeType _type)\n        : type(_type)\n        , min(0, 0, 0)\n        , size(0)\n        , drawInfo(nullptr) {\n        memset(children, 0, sizeof(children));\n    }\n\n    OctreeNodeType\ttype;\n    i32v3\t\t\tmin;\n    int\t\t\t\tsize;\n    OctreeNode*\t\tchildren[8];\n    OctreeDrawInfo*\tdrawInfo;\n};\n\n// ----------------------------------------------------------------------------\n\nOctreeNode* BuildOctree(const i32v3& min, const int size, const float threshold);\nvoid DestroyOctree(OctreeNode* node);\nvoid GenerateMeshFromOctree(OctreeNode* node, std::vector<VoxelModelVertex>& vertexBuffer, std::vector<ui32>& indexBuffer);\n\n// ----------------------------------------------------------------------------\n\n#endif\t// HAS_OCTREE_H_BEEN_INCLUDED\n"
  },
  {
    "path": "SoA/OpaqueVoxelRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"OpaqueVoxelRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/ShaderManager.h>\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"BlockPack.h\"\n#include \"BlockTexturePack.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkRenderer.h\"\n#include \"GameRenderParams.h\"\n#include \"SoaOptions.h\"\n#include \"RenderUtils.h\"\n#include \"soaUtils.h\"\n#include \"ShaderLoader.h\"\n\nvoid OpaqueVoxelRenderStage::hook(ChunkRenderer* renderer, const GameRenderParams* gameRenderParams) {\n    m_gameRenderParams = gameRenderParams;\n    m_renderer = renderer;\n}\n\nvoid OpaqueVoxelRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    ChunkMeshManager* cmm = m_gameRenderParams->chunkMeshmanager;\n\n    const f64v3& position = m_gameRenderParams->chunkCamera->getPosition();\n\n    m_renderer->beginOpaque(m_gameRenderParams->blockTexturePack->getAtlasTexture(), m_gameRenderParams->sunlightDirection,\n                            m_gameRenderParams->sunlightColor);\n    \n    // f64v3 closestPoint;\n    // static const f64v3 boxDims(CHUNK_WIDTH);\n    static const f64v3 boxDims_2(CHUNK_WIDTH / 2);\n    const std::vector <ChunkMesh *>& chunkMeshes = cmm->getChunkMeshes();\n    {\n        std::lock_guard<std::mutex> l(cmm->lckActiveChunkMeshes);\n        if (chunkMeshes.empty()) return;\n        for (int i = chunkMeshes.size() - 1; i >= 0; i--) {\n            ChunkMesh* cm = chunkMeshes[i];\n\n            if (m_gameRenderParams->chunkCamera->sphereInFrustum(f32v3(cm->position + boxDims_2 - position), CHUNK_DIAGONAL_LENGTH)) {\n                // TODO(Ben): Implement perfect fade\n                cm->inFrustum = 1;\n                m_renderer->drawOpaque(cm, position,\n                                       m_gameRenderParams->chunkCamera->getViewProjectionMatrix());\n            } else {\n                cm->inFrustum = 0;\n            }\n        }\n    }\n    \n    m_renderer->end();\n}\n"
  },
  {
    "path": "SoA/OpaqueVoxelRenderStage.h",
    "content": "/// \n///  OpaqueVoxelRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the render stage for opaque voxels.\n///  Opaque voxels have no transparency.\n///\n\n#pragma once\n\n#ifndef OpaqueVoxelRenderStage_h__\n#define OpaqueVoxelRenderStage_h__\n\n#include \"IRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\nclass Camera;\nclass ChunkRenderer;\nclass GameRenderParams;\nclass MeshManager;\n\nclass OpaqueVoxelRenderStage : public IRenderStage\n{\npublic:\n    void hook(ChunkRenderer* renderer, const GameRenderParams* gameRenderParams);\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera) override;\nprivate:\n    ChunkRenderer* m_renderer;\n    const GameRenderParams* m_gameRenderParams; ///< Handle to some shared parameters\n};\n\n#endif // OpaqueVoxelRenderStage_h__"
  },
  {
    "path": "SoA/OptionsController.cpp",
    "content": "#include \"stdafx.h\"\n#include \"OptionsController.h\"\n\n#include <fstream>\n\nOptionsController::OptionsController(const nString& filePath /*= \"Data/options.ini\"*/) :\n    m_filePath(filePath) {\n    // Empty\n}\n\nOptionsController::~OptionsController() {\n    // Empty\n}\n\nvoid OptionsController::setDefault() {\n    m_tempCopy = soaOptions;\n    m_default = soaOptions; // TODO(Ben): This is wrong\n}\n\nvoid OptionsController::beginContext() {\n    m_tempCopy = soaOptions;\n}\n\n// TODO(Ben): Better parsing\nbool OptionsController::loadOptions() {\n    std::ifstream file(m_filePath);\n    if (file.fail()) return false;\n    nString token;\n    nString dummy;\n    while (std::getline(file, token, ':')) {\n        int id = soaOptions.findID(token);\n        if (id != -1) {\n            SoaOption& opt = soaOptions.get(id);\n            switch (opt.value.type) {\n                case OptionValueType::F32:\n                    file >> opt.value.f; break;\n                case OptionValueType::I32:\n                    file >> opt.value.i; break;\n                case OptionValueType::BOOL:\n                    file >> opt.value.b; break;\n                case OptionValueType::CHAR:\n                    file >> opt.value.c; break;\n                default:\n                    file >> dummy; break;\n            }\n            char nl;\n            file.get(nl);\n        }\n    }\n    return true;\n}\n\nvoid OptionsController::saveOptions() {\n    soaOptions = m_tempCopy;\n    OptionsChange();\n\n    std::ofstream file(m_filePath);\n    if (file.fail()) return;\n\n    auto& options = soaOptions.getOptions();\n    for (int id = 0; id < (int)options.size(); id++) {\n        auto& opt = options[id];\n        // Don't duplicated app.config\n        if (id != OPT_SCREEN_HEIGHT && id != OPT_SCREEN_WIDTH &&\n            id != OPT_FULLSCREEN && id != OPT_BORDERLESS && id != OPT_VSYNC) {\n            file << opt.name << \": \";\n            switch (opt.value.type) {\n                case OptionValueType::F32:\n                    file << opt.value.f << '\\n'; break;\n                case OptionValueType::I32:\n                    file << opt.value.i << '\\n'; break;\n                case OptionValueType::BOOL:\n                    file << opt.value.b << '\\n'; break;\n                case OptionValueType::CHAR:\n                    file << opt.value.c << '\\n'; break;\n                default:\n                    break;\n            }\n        }\n    }\n}\n\nvoid OptionsController::restoreDefault() {\n    soaOptions = m_default;\n    m_tempCopy = m_default;\n    OptionsChange();\n}\n\nvoid OptionsController::setInt(nString optionName, int val) {\n    auto& option = m_tempCopy.get(optionName);\n    if (option.value.i != val) {\n        option.value.i = val;\n    }\n}\n\nvoid OptionsController::setFloat(nString optionName, f32 val) {\n    auto& option = m_tempCopy.get(optionName);\n    if (option.value.f != val) {\n        option.value.f = val;\n    }\n}\n\nvoid OptionsController::setBool(nString optionName, bool val) {\n    auto& option = m_tempCopy.get(optionName);\n    if (option.value.b != val) {\n        option.value.b = val;\n    }\n}\n\nint OptionsController::getInt(nString optionName) {\n    return m_tempCopy.get(optionName).value.i;\n}\n\nf32 OptionsController::getFloat(nString optionName) {\n    return m_tempCopy.get(optionName).value.f;\n}\n\nbool OptionsController::getBool(nString optionName) {\n    return m_tempCopy.get(optionName).value.b;\n}\n"
  },
  {
    "path": "SoA/OptionsController.h",
    "content": "///\n/// OptionsController.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 13 May 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Handles changing of options.\n///\n\n#pragma once\n\n#ifndef OptionsController_h__\n#define OptionsController_h__\n\n#include \"SoaOptions.h\"\n#include <Vorb/Event.hpp>\n#include <Vorb/script/IEnvironment.hpp>\n\nclass OptionsController {\npublic:\n    OptionsController(const nString& filePath = \"Data/options.ini\");\n    ~OptionsController();\n\n    // Call right before loading options\n    void setDefault();\n\n    /// Begins a context for changing options.\n    /// Call this when beginning to change options.\n    void beginContext();\n\n    bool loadOptions();\n\n    void saveOptions();\n\n    void restoreDefault();\n\n    template <typename ScriptImpl>\n    void registerScripting(vscript::IEnvironment<ScriptImpl>* env);\n\n    // These can be called from lua scripts\n    void setInt(nString optionName, int val);\n    void setFloat(nString optionName, f32 val);\n    void setBool(nString optionName, bool val);\n    int getInt(nString optionName);\n    f32 getFloat(nString optionName);\n    bool getBool(nString optionName);\n    \n    bool needsFboReload = false;\n    bool needsTextureReload = false;\n    bool needsShaderReload = false;\n    bool needsWindowReload = false;\n\n    Event<> OptionsChange;\n\nprivate:\n    nString m_filePath = \"\";\n    SoaOptions m_tempCopy;\n    SoaOptions m_default;\n};\n\ntemplate <typename ScriptImpl>\nvoid OptionsController::registerScripting(vscript::IEnvironment<ScriptImpl>* env) {\n    env->setNamespaces(\"Options\");\n    env->addCDelegate(\"setInt\",         makeDelegate(this, &OptionsController::setInt));\n    env->addCDelegate(\"setFloat\",       makeDelegate(this, &OptionsController::setFloat));\n    env->addCDelegate(\"setBool\",        makeDelegate(this, &OptionsController::setBool));\n    env->addCDelegate(\"getInt\",         makeDelegate(this, &OptionsController::getInt));\n    env->addCDelegate(\"getFloat\",       makeDelegate(this, &OptionsController::getFloat));\n    env->addCDelegate(\"getBool\",        makeDelegate(this, &OptionsController::getBool));\n    env->addCDelegate(\"beginContext\",   makeDelegate(this, &OptionsController::beginContext));\n    env->addCDelegate(\"save\",           makeDelegate(this, &OptionsController::saveOptions));\n    env->addCDelegate(\"load\",           makeDelegate(this, &OptionsController::loadOptions));\n    env->addCDelegate(\"restoreDefault\", makeDelegate(this, &OptionsController::restoreDefault));\n    env->setNamespaces();\n}\n\n#endif // OptionsController_h__\n\n"
  },
  {
    "path": "SoA/OrbitComponentRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"OrbitComponentRenderer.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/utils.h>\n\n#include \"Constants.h\"\n#include \"RenderUtils.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"OrbitComponentUpdater.h\"\n\nvoid OrbitComponentRenderer::drawPath(OrbitComponent& cmp, vg::GLProgram& colorProgram, const f32m4& wvp, NamePositionComponent* npComponent VORB_MAYBE_UNUSED, const f64v3& camPos, float blendFactor, NamePositionComponent* parentNpComponent /*= nullptr*/) {\n\n    // Lazily generate mesh\n    if (cmp.vbo == 0) generateOrbitEllipse(cmp, colorProgram);\n    if (cmp.numVerts == 0) return;\n    \n    f32m4 w(1.0f);\n    if (parentNpComponent) {\n        setMatrixTranslation(w, parentNpComponent->position - camPos);\n    } else {\n        setMatrixTranslation(w, -camPos);\n    }\n    \n    f32m4 pathMatrix = wvp * w;\n\n    f32v4 newColor = lerp(cmp.pathColor[0], cmp.pathColor[1], blendFactor);\n    if (newColor.a <= 0.0f) return;\n    glUniform4f(colorProgram.getUniform(\"unColor\"), newColor.r, newColor.g, newColor.b, newColor.a);\n\n    glUniformMatrix4fv(colorProgram.getUniform(\"unWVP\"), 1, GL_FALSE, &pathMatrix[0][0]);\n\n    float currentAngle = cmp.currentMeanAnomaly - (f32)cmp.startMeanAnomaly;\n    glUniform1f(colorProgram.getUniform(\"currentAngle\"), currentAngle / (float)M_2_PI);\n\n    // Draw the ellipse\n    glDepthMask(false);\n    glBindVertexArray(cmp.vao);\n    glDrawArrays(GL_LINE_STRIP, 0, cmp.numVerts);\n    glBindVertexArray(0);\n    glDepthMask(true);\n}\n\nvoid OrbitComponentRenderer::generateOrbitEllipse(OrbitComponent& cmp, vg::GLProgram& colorProgram) {\n\n    if (cmp.verts.empty()) return;\n\n    glGenVertexArrays(1, &cmp.vao);\n    glBindVertexArray(cmp.vao);\n\n    colorProgram.enableVertexAttribArrays();\n\n    // Upload the buffer data\n    vg::GpuMemory::createBuffer(cmp.vbo);\n    vg::GpuMemory::bindBuffer(cmp.vbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(cmp.vbo,\n                                    vg::BufferTarget::ARRAY_BUFFER,\n                                    cmp.verts.size() * sizeof(OrbitComponent::Vertex),\n                                    cmp.verts.data(),\n                                    vg::BufferUsageHint::STATIC_DRAW);\n    vg::GpuMemory::bindBuffer(0, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(OrbitComponent::Vertex), 0);\n    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(OrbitComponent::Vertex), (const void*)offsetof(OrbitComponent::Vertex, angle));\n    glBindVertexArray(0);\n    cmp.numVerts = cmp.verts.size();\n    std::vector<OrbitComponent::Vertex>().swap(cmp.verts);\n}"
  },
  {
    "path": "SoA/OrbitComponentRenderer.h",
    "content": "///\n/// OrbitComponentRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renders orbit components\n///\n\n#pragma once\n\n#ifndef OrbitComponentRenderer_h__\n#define OrbitComponentRenderer_h__\n\n#include <Vorb/types.h>\n#include <Vorb/VorbPreDecl.inl>\n\nclass SpaceSystem;\nstruct OrbitComponent;\nstruct NamePositionComponent;\n\nDECL_VG(class GLProgram)\n\nclass OrbitComponentRenderer {\npublic:\n    /// Draws the ellipse\n    void drawPath(OrbitComponent& cmp, vg::GLProgram& colorProgram, const f32m4& WVP, NamePositionComponent* npComponent,\n                  const f64v3& camPos, float blendFactor, NamePositionComponent* parentNpComponent = nullptr);\nprivate:\n    void generateOrbitEllipse(OrbitComponent& cmp, vg::GLProgram& colorProgram);\n};\n\n#endif // OrbitComponentRenderer_h__"
  },
  {
    "path": "SoA/OrbitComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"OrbitComponentUpdater.h\"\n#include \"SpaceSystem.h\"\n\n#include \"Constants.h\"\n#include \"soaUtils.h\"\n\nvoid OrbitComponentUpdater::update(SpaceSystem* spaceSystem, f64 time) {\n    for (auto& it : spaceSystem->orbit) {\n        auto& cmp = it.second;\n        if (cmp.parentOrbId) {\n            OrbitComponent* pOrbC = &spaceSystem->orbit.get(cmp.parentOrbId);\n            updatePosition(cmp, time, &spaceSystem->namePosition.get(cmp.npID),\n                              pOrbC,\n                              &spaceSystem->namePosition.get(pOrbC->npID));\n        } else {\n            updatePosition(cmp, time, &spaceSystem->namePosition.get(cmp.npID));\n        }\n    }\n}\n\nvoid OrbitComponentUpdater::updatePosition(OrbitComponent& cmp, f64 time, NamePositionComponent* npComponent,\n                                              OrbitComponent* parentOrbComponent /* = nullptr */,\n                                              NamePositionComponent* parentNpComponent /* = nullptr */) {\n    if (cmp.a == 0.0) return;\n    /// Calculates position as a function of time\n    /// http://en.wikipedia.org/wiki/Kepler%27s_laws_of_planetary_motion#Position_as_a_function_of_time\n\n    // 1. Calculate the mean anomaly\n    f64 meanAnomaly = (M_2_PI / cmp.t) * time + cmp.startMeanAnomaly;\n    cmp.currentMeanAnomaly = (f32)meanAnomaly;\n\n    f64 v = calculateTrueAnomaly(meanAnomaly, cmp.e);\n  \n    // Calculate radius\n    // http://www.stargazing.net/kepler/ellipse.html\n    f64 r = cmp.a * (1.0 - cmp.e * cmp.e) / (1.0 + cmp.e * cos(v));\n    \n    f64 w = cmp.p - cmp.o; ///< Argument of periapsis\n\n    // Calculate position\n    f64v3 position;\n    f64 cosv = cos(v + cmp.p - cmp.o);\n    f64 sinv = sin(v + cmp.p - cmp.o);\n    f64 coso = cos(cmp.o);\n    f64 sino = sin(cmp.o);\n    f64 cosi = cos(cmp.i);\n    f64 sini = sin(cmp.i);\n    position.x = r * (coso * cosv - sino * sinv * cosi);\n    position.y = r * (sinv * sini);\n    position.z = r * (sino * cosv + coso * sinv * cosi);\n\n    // Calculate velocity\n    f64 g = sqrt(M_G * KM_PER_M * cmp.parentMass * (2.0 / r - 1.0 / cmp.a)) * KM_PER_M;\n    f64 sinwv = sin(w + v);\n    cmp.relativeVelocity.x = -g * sinwv * cosi;\n    cmp.relativeVelocity.y = g * sinwv * sini;\n    cmp.relativeVelocity.z = g * cos(w + v);\n\n    // If this planet has a parent, make it parent relative\n    if (parentOrbComponent) {\n        cmp.velocity = parentOrbComponent->velocity + cmp.relativeVelocity;\n        npComponent->position = position + parentNpComponent->position;\n    } else {\n        cmp.velocity = cmp.relativeVelocity;\n        npComponent->position = position;\n    }\n}\n\nf64 OrbitComponentUpdater::calculateTrueAnomaly(f64 meanAnomaly, f64 e) {\n    // 2. Solve Kepler's equation to compute eccentric anomaly \n    // using Newton's method\n    // http://www.jgiesen.de/kepler/kepler.html\n#define ITERATIONS 3\n    f64 E; ///< Eccentric Anomaly\n    f64 F;\n    E = meanAnomaly;\n    for (int n = 0; n < ITERATIONS; n++) {\n        F = E - e * sin(E) - meanAnomaly;\n        E -= F / (1.0 - e * cos(E));\n    }\n    // 3. Calculate true anomaly\n    return atan2(sqrt(1.0 - e * e) * sin(E), cos(E) - e);\n}\n"
  },
  {
    "path": "SoA/OrbitComponentUpdater.h",
    "content": "///\n/// OrbitComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates OrbitComponents\n///\n\n#pragma once\n\n#ifndef OrbitComponentUpdater_h__\n#define OrbitComponentUpdater_h__\n\n#include <Vorb/types.h>\n\nclass SpaceSystem;\nstruct NamePositionComponent;\nstruct OrbitComponent;\nstruct SphericalGravityComponent;\n\nclass OrbitComponentUpdater {\npublic:\n    void update(SpaceSystem* spaceSystem, f64 time);\n\n    /// Updates the position based on time and parent position\n    /// @param cmp: The component to update\n    /// @param time: Time in seconds\n    /// @param npComponent: The positional component of this component\n    /// @param parentNpComponent: The parents positional component\n    void updatePosition(OrbitComponent& cmp, f64 time, NamePositionComponent* npComponent,\n                           OrbitComponent* parentOrbComponent = nullptr,\n                           NamePositionComponent* parentNpComponent = nullptr);\n\n    f64 calculateTrueAnomaly(f64 meanAnomaly, f64 e);\n};\n\n#endif // OrbitComponentUpdater_h__"
  },
  {
    "path": "SoA/PDA.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PDA.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\n#include \"GamePlayScreen.h\"\n#include \"ShaderLoader.h\"\n\nPDA::PDA() {\n    // Empty\n}\nPDA::~PDA() {\n    // Empty\n}\n\nvoid PDA::init(GameplayScreen* ownerScreen VORB_UNUSED) {\n    // Initialize the user interface\n}\n\nvoid PDA::open() {\n\n    _isOpen = true;\n}\n\nvoid PDA::close() {\n\n    _isOpen = false;\n}\n\nvoid PDA::update() {\n\n}\n\nvoid PDA::draw() const {\n    if (!m_program) ShaderLoader::createProgramFromFile(\"Shaders/TextureShading/Texture2dShader.vert\",\n                                                             \"Shaders/TextureShading/Texture2dShader.frag\");\n\n}\n\nvoid PDA::destroy() {\n\n}"
  },
  {
    "path": "SoA/PDA.h",
    "content": "// \n//  PDA.h\n//  Seed Of Andromeda\n//\n//  Created by Ben Arnold on 26 Oct 2014\n//  Copyright 2014 Regrowth Studios\n//  MIT License\n//  \n//  This file provides the implementation for the\n//  PDA.\n//\n\n#pragma once\n\n#ifndef PDA_H_\n#define PDA_H_\n\n#include <SDL2/SDL.h>\n#include <Vorb/VorbPreDecl.inl>\n\n#include \"Computer.h\"\n\nclass GameplayScreen;\n\nenum class PdaState { BIOMETRICS, INVENTORY, DATA, CODEX, COMMUNICATIONS, SCANNER };\n\nDECL_VG(class GLProgram)\n\nclass PDA : public Computer\n{\npublic:\n    PDA();\n    ~PDA();\n\n    /// Initializes the PDA\n    /// @param ownerScreen: The screen that owns this PDA\n    void init(GameplayScreen* ownerScreen);\n\n    /// Opens the PDA\n    void open();\n\n    /// Closes the PDA\n    void close();\n\n    /// Updates the PDA\n    void update();\n\n    /// Draws the PDA\n    void draw() const;\n\n    /// Handles an event\n    /// @param e: The event to handle\n    void onEvent(const SDL_Event& e);\n\n    /// Frees all resources\n    void destroy();\n\n    /// Returns true if it is open\n    bool isOpen() const { return _isOpen; }\nprivate:\n    vg::GLProgram* m_program = nullptr;\n    bool _isOpen = false;\n};\n\n#endif // PDA_H_"
  },
  {
    "path": "SoA/ParkourComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ParkourComponentUpdater.h\"\n\n#define GLM_FORCE_RADIANS\n\n#include \"GameSystem.h\"\n#include \"SpaceSystem.h\"\n#include \"VoxelUtils.h\"\n#include \"SoAState.h\"\n\nvoid ParkourComponentUpdater::update(GameSystem* gameSystem, SpaceSystem* spaceSystem VORB_UNUSED, const SoaState *soaState) {\n    for (auto& it : gameSystem->parkourInput) {\n        auto& parkour = it.second;\n        auto& physics = gameSystem->physics.get(parkour.physicsComponent);\n        if (physics.voxelPosition == 0) return;\n\n        auto& attributes = gameSystem->attributes.get(parkour.attributeComponent);\n        auto& voxelPosition = gameSystem->voxelPosition.get(physics.voxelPosition);\n        auto& head = gameSystem->head.get(parkour.headComponent);\n        auto& aabbCollidable = gameSystem->aabbCollidable.get(parkour.aabbCollidable);\n\n        f64 deltaTime;\n\n        if(m_lastTime<0.0f)\n            deltaTime=0.0f;\n        else\n            deltaTime=soaState->time-m_lastTime;\n        m_lastTime=soaState->time;\n\n        // TODO(Ben): Timestep\n        // TODO(Ben): Account mass\n        // f64 acceleration = 1.0 + attributes.agility * 0.01;\n        f64 maxSpeed = 0.5 + attributes.agility * 0.005;\n        if (parkour.crouch) {\n            maxSpeed *= 0.3f;\n        } else if (parkour.sprint) {\n            maxSpeed *= 2.0f;\n        }\n\n        f64v3 targetVel(0.0);\n        int inputCount = 0;\n\n        // Get move direction\n        // TODO(Ben): Gamepad support\n        if (parkour.moveForward) {\n            targetVel.z = 1.0f;\n            inputCount++;\n        } else if (parkour.moveBackward) {\n            targetVel.z = -1.0f;\n            inputCount++;\n        }\n\n        if (parkour.moveLeft) {\n            targetVel.x = 1.0f;\n            inputCount++;\n        } else if (parkour.moveRight) {\n            targetVel.x = -1.0f;\n            inputCount++;\n        }\n\n        // Get angles\n        f64v3& euler = voxelPosition.eulerAngles;\n\n        if (inputCount != 0) {\n            // Normalize for diagonal\n            if (inputCount == 2) {\n                targetVel = glm::normalize(targetVel);\n            }\n            // Use head yaw for body when moving\n            euler.y += head.eulerAngles.y;\n            head.eulerAngles.y = 0.0f;\n            head.relativeOrientation = f64q(head.eulerAngles);\n        }\n\n        // Check for pitch (Should be no pitch)\n        if (euler.x != 0.0) {\n            euler.x *= 0.95;\n            if (ABS(euler.x) < 0.01) {\n                euler.x = 0.0;\n            }\n        }\n        // Check for roll (Should be no roll)\n        if (euler.z != 0.0) {\n            euler.z *= 0.95;\n            if (ABS(euler.z) < 0.01) {\n                euler.z = 0.0;\n            }\n        }\n\n        voxelPosition.orientation = f64q(euler);\n\n        targetVel *= (maxSpeed*deltaTime);\n        targetVel = voxelPosition.orientation * targetVel;\n\n        static const f64 step = 0.1;\n        f64v3 dVel = targetVel - f64v3(physics.velocity.x, 0.0f, physics.velocity.z);\n        f64 l = glm::length(dVel);\n        if (l < step) {\n            physics.velocity.x = targetVel.x;\n            physics.velocity.z = targetVel.z;\n        } else {\n            physics.velocity += dVel * step;\n        }\n\n        // Collision\n        if (aabbCollidable.voxelCollisions.size() && voxelPosition.parentVoxel) {\n            \n            const f64v3 MIN_DISTANCE = f64v3(aabbCollidable.box) * 0.5 + 0.5;\n\n            for (auto& it : aabbCollidable.voxelCollisions) {\n                for (auto& cd : it.second) {\n                    f64v3 aabbPos = voxelPosition.gridPosition.pos + f64v3(aabbCollidable.offset);\n\n                    f64v3 vpos = f64v3(it.first.x, it.first.y, it.first.z) * (f64)CHUNK_WIDTH + f64v3(getPosFromBlockIndex(cd.index)) + 0.5;\n                        \n                    f64v3 dp = vpos - aabbPos;\n                    f64v3 adp(glm::abs(dp));\n\n                   // std::cout << MIN_DISTANCE.y - adp.y << std::endl;\n\n                    // Check slow feet collision first\n                    if (dp.y < 0 && MIN_DISTANCE.y - adp.y < 0.55 && !cd.top) {\n                        voxelPosition.gridPosition.y += (MIN_DISTANCE.y - adp.y) * 0.01;\n                        if (physics.velocity.y < 0) physics.velocity.y = 0.0;\n                        continue;\n                    }\n                    if (adp.y > adp.z && adp.y > adp.x) {\n                        // Y collision\n                        if (dp.y < 0) {\n                            if (!cd.top) {\n                                voxelPosition.gridPosition.y += MIN_DISTANCE.y - adp.y;\n                                if (physics.velocity.y < 0) physics.velocity.y = 0.0;\n                                continue;\n                            }\n                        } else {\n                            if (!cd.bottom) {\n                                voxelPosition.gridPosition.y -= MIN_DISTANCE.y - adp.y;\n                                if (physics.velocity.y > 0) physics.velocity.y = 0.0;\n                                continue;\n                            }\n                        }\n                    }\n                    if (adp.z > adp.x) {\n                        // Z collision\n                        if (dp.z < 0) {\n                            if (!cd.front) {\n                                voxelPosition.gridPosition.z += MIN_DISTANCE.z - adp.z;\n                                if (physics.velocity.z < 0) physics.velocity.z = 0.0;\n                                continue;\n                            }\n                        } else {\n                            if (!cd.back) {\n                                voxelPosition.gridPosition.z -= MIN_DISTANCE.z - adp.z;\n                                if (physics.velocity.z > 0) physics.velocity.z = 0.0;\n                                continue;\n                            }\n                        }\n                    }\n                    // X collision\n                    if (dp.x < 0) {\n                        if (!cd.right) {\n                            voxelPosition.gridPosition.x += MIN_DISTANCE.x - adp.x;\n                            if (physics.velocity.x < 0) physics.velocity.x = 0.0;\n                        }\n                    } else {\n                        if (!cd.left) {\n                            voxelPosition.gridPosition.x -= MIN_DISTANCE.x - adp.x;\n                            if (physics.velocity.x > 0) physics.velocity.x = 0.0;\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "SoA/ParkourComponentUpdater.h",
    "content": "///\n/// ParkourComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates ParkourComponents\n///\n\n#pragma once\n\n#include <Vorb/types.h>\n\n#ifndef ParkourComponentUpdater_h__\n#define ParkourComponentUpdater_h__\n\nclass GameSystem;\nclass SpaceSystem;\nstruct SoaState;\n\nclass ParkourComponentUpdater {\npublic:\n    ParkourComponentUpdater():m_lastTime(-1.0f) {}\n\n    void update(GameSystem* gameSystem, SpaceSystem* spaceSystem, const SoaState *soaState);\n\n    f64 m_lastTime;\n};\n\n#endif // ParkourComponentUpdater_h__\n\n"
  },
  {
    "path": "SoA/ParticleMesh.h",
    "content": "#pragma once\n#include \"WorldStructs.h\"\n\nstatic const GLubyte particleUVs[12] = {255, 255, 0, 255, 0, 0, 0, 0, 255, 0, 255, 255};\n\nclass ParticleMesh {\npublic:\n    ParticleMesh(): uvBufferID(0), billboardVertexBufferID(0), vecIndex(-1), size(0), animated(0) {}\n\n    GLuint uvBufferID, billboardVertexBufferID;\n    int vecIndex, size, X, Y, Z, type;\n    std::vector <int> usedParticles;\n    bool animated;\n};\n\nclass ParticleMeshMessage {\npublic:\n    ParticleMeshMessage(): mesh(NULL) {}\n\n    ParticleMesh *mesh;\n    std::vector <BillboardVertex> verts;\n    std::vector <int> usedParticles;\n    int size, X, Y, Z;\n};"
  },
  {
    "path": "SoA/PauseMenu.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PauseMenu.h\"\n\n#include \"GamePlayScreen.h\"\n#include \"ShaderLoader.h\"\n\nPauseMenu::PauseMenu() {\n    // Empty\n}\n\nPauseMenu::~PauseMenu() {\n    // Empty\n}\n\nvoid PauseMenu::init(GameplayScreen* ownerScreen VORB_UNUSED) {\n\n}\n\nvoid PauseMenu::open() {\n    _isOpen = true;\n}\n\nvoid PauseMenu::close() {\n    if (_isOpen) {\n        _isOpen = false;\n    }\n}\n\nvoid PauseMenu::update() {\n\n}\n\nvoid PauseMenu::draw() const {\n    if (!m_program) ShaderLoader::createProgramFromFile(\"Shaders/TextureShading/Texture2dShader.vert\",\n                                                             \"Shaders/TextureShading/Texture2dShader.frag\");\n\n}\n\nvoid PauseMenu::destroy() {\n\n}"
  },
  {
    "path": "SoA/PauseMenu.h",
    "content": "///\n/// PauseMenu.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 30 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Pause menu implementation for use in GamePlayScreen\n///\n\n#pragma once\n\n#ifndef PauseMenu_h__\n#define PauseMenu_h__\n\n#include <Vorb/VorbPreDecl.inl>\n\nDECL_VG(class GLProgram);\nclass GameplayScreen;\n\n\nclass PauseMenu {\npublic:\n    PauseMenu();\n    ~PauseMenu();\n\n    /// Initializes the Pause Menu\n    /// @param ownerScreen: The screen that owns this pause menu\n    void init(GameplayScreen* ownerScreen);\n\n    /// Opens the Pause Menu\n    void open();\n\n    /// Closes the Pause Menu\n    void close();\n\n    /// Updates the Pause Menu\n    void update();\n\n    /// Draws the Pause Menu\n    void draw() const;\n\n    /// Handles an event\n    /// @param e: The event to handle\n    //void onEvent(const SDL_Event& e);\n\n    /// Frees all resources\n    void destroy();\n\n    /// Returns true if the Pause Menu is open\n    const bool& isOpen() const { return _isOpen; }\nprivate:\n    vg::GLProgram* m_program = nullptr;\n    bool _isOpen = false;\n};\n\n#endif // PauseMenu_h__"
  },
  {
    "path": "SoA/PauseMenuRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PauseMenuRenderStage.h\"\n\n#include \"PauseMenu.h\"\n\nvoid PauseMenuRenderStage::hook(const PauseMenu* pauseMenu) {\n    _pauseMenu = pauseMenu;\n}\n\nvoid PauseMenuRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED /*= nullptr*/) {\n    if (_pauseMenu->isOpen()) {\n        _pauseMenu->draw();\n    }\n}"
  },
  {
    "path": "SoA/PauseMenuRenderStage.h",
    "content": "///\n/// PauseMenuRenderStage.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 30 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Render stage for drawing the pause menu\n///\n\n#pragma once\n\n#ifndef PauseMenuRenderStage_h__\n#define PauseMenuRenderStage_h__\n\n#include \"IRenderStage.h\"\n\nclass PauseMenu;\n\nclass PauseMenuRenderStage : public IRenderStage {\npublic:\n    void hook(const PauseMenu* pauseMenu);\n\n    // Draws the render stage\n    virtual void render(const Camera* camera = nullptr) override;\n\nprivate:\n    const PauseMenu* _pauseMenu = nullptr; ///< Handle to pause menu for rendering\n};\n\n#endif // PauseMenuRenderStage_h__"
  },
  {
    "path": "SoA/PdaRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PdaRenderStage.h\"\n\n#include \"PDA.h\"\n\n\nPdaRenderStage::PdaRenderStage() {\n    // Empty\n}\n\nvoid PdaRenderStage::hook(const PDA* pda) {\n    _pda = pda;\n}\n\nvoid PdaRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    if (_pda->isOpen()) {\n        _pda->draw();\n    }\n}\n"
  },
  {
    "path": "SoA/PdaRenderStage.h",
    "content": "/// \n///  PdaRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 2 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the render stage for PDA rendering\n///\n\n#pragma once\n\n#ifndef PdaRenderStage_h__\n#define PdaRenderStage_h__\n\n#include \"IRenderStage.h\"\n\nclass PDA;\n\nclass PdaRenderStage : public IRenderStage {\npublic:\n    PdaRenderStage();\n\n    void hook(const PDA* pda);\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera) override;\nprivate:\n    const PDA* _pda = nullptr; ///< Handle to the PDA\n};\n\n#endif // PdaRenderStage_h__"
  },
  {
    "path": "SoA/PhysicsBlockRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PhysicsBlockRenderStage.h\"\n\n#include \"Camera.h\"\n#include \"ChunkRenderer.h\"\n#include \"GameRenderParams.h\"\n#include \"SoaOptions.h\"\n\n// TODO: Do we still want this as is? If so, reimplement and remove VORB_UNUSED tags.\n\nPhysicsBlockRenderStage::PhysicsBlockRenderStage(GameRenderParams* gameRenderParams VORB_UNUSED, \n                                                 const std::vector<PhysicsBlockMesh*>& physicsBlockMeshes VORB_UNUSED,\n                                                 vg::GLProgram* glProgram VORB_UNUSED) //:\n//    _gameRenderParams(gameRenderParams),\n//    _physicsBlockMeshes(physicsBlockMeshes),\n//    _glProgram(glProgram) \n{\n    // Empty\n}\n\nvoid PhysicsBlockRenderStage::render(const Camera* camera VORB_UNUSED) {\n\n    /* _glProgram->use();\n\n     glUniform1f(_glProgram->getUniform(\"lightType\"), _gameRenderParams->lightActive);\n\n     glUniform1f(_glProgram->getUniform(\"alphaMult\"), 1.0f);\n\n     glUniform3fv(_glProgram->getUniform(\"eyeNormalWorldspace\"), 1, &(_gameRenderParams->chunkCamera->getDirection()[0]));\n     glUniform1f(_glProgram->getUniform(\"fogEnd\"), _gameRenderParams->fogEnd);\n     glUniform1f(_glProgram->getUniform(\"fogStart\"), _gameRenderParams->fogStart);\n     glUniform3fv(_glProgram->getUniform(\"fogColor\"), 1, &(_gameRenderParams->fogColor[0]));\n     glUniform3fv(_glProgram->getUniform(\"lightPosition_worldspace\"), 1, &(_gameRenderParams->sunlightDirection[0]));\n     glUniform1f(_glProgram->getUniform(\"specularExponent\"), soaOptions.get(OPT_SPECULAR_EXPONENT).value.f);\n     glUniform1f(_glProgram->getUniform(\"specularIntensity\"), soaOptions.get(OPT_SPECULAR_INTENSITY).value.f * 0.3f);\n\n     glUniform1f(_glProgram->getUniform(\"sunVal\"), _gameRenderParams->sunlightIntensity);\n\n     float blockAmbient = 0.000f;\n     glUniform3f(_glProgram->getUniform(\"ambientLight\"), blockAmbient, blockAmbient, blockAmbient);\n     glUniform3fv(_glProgram->getUniform(\"lightColor\"), 1, &(_gameRenderParams->sunlightColor[0]));\n\n     glUniform1f(_glProgram->getUniform(\"fadeDistance\"), (GLfloat)soaOptions.get(OPT_VOXEL_RENDER_DISTANCE).value.f - 12.5f);\n\n     for (size_t i = 0; i < _physicsBlockMeshes.size(); i++) {\n     PhysicsBlockBatch::draw(_physicsBlockMeshes[i], _glProgram, _gameRenderParams->chunkCamera->getPosition(),\n     _gameRenderParams->chunkCamera->getViewProjectionMatrix());\n     }\n\n     _glProgram->unuse();*/\n}\n\n"
  },
  {
    "path": "SoA/PhysicsBlockRenderStage.h",
    "content": "///\n/// PhysicsBlockRenderStage.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 9 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// This file implements the physics block rendering,\n///\n\n#pragma once\n\n#ifndef PhysicsBlockRenderStage_h__\n#define PhysicsBlockRenderStage_h__\n\n#include <Vorb/graphics/GLProgram.h>\n\n#include \"IRenderStage.h\"\n\nclass GameRenderParams;\nclass PhysicsBlockMesh;\n\nclass PhysicsBlockRenderStage : public IRenderStage {\npublic:\n    /// Construcst the stage and injects dependencies\n    /// @param gameRenderParams: Some shared parameters\n    /// @param physicsBlockMeshes: Handle to the list of meshes to render\n    /// @param glProgram: The program used to draw physics blocks\n    PhysicsBlockRenderStage(GameRenderParams* gameRenderParams, \n                            const std::vector<PhysicsBlockMesh*>& physicsBlockMeshes,\n                            vg::GLProgram* glProgram);\n\n    // Draws the render stage\n    virtual void render(const Camera* camera) override;\n\nprivate:\n//    vg::GLProgram* _glProgram; ///< Shader program that renders the voxels\n//    GameRenderParams* _gameRenderParams; ///< Some shared voxel rendering params\n//    const std::vector<PhysicsBlockMesh*>& _physicsBlockMeshes; ///< The meshes to render\n};\n\n\n#endif // PhysicsBlockRenderStage_h__"
  },
  {
    "path": "SoA/PhysicsComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PhysicsComponentUpdater.h\"\n\n#include \"GameSystem.h\"\n#include \"GameSystemAssemblages.h\"\n#include \"SpaceSystem.h\"\n#include \"TerrainPatch.h\"\n#include \"VoxelSpaceConversions.h\"\n#include \"VoxelSpaceUtils.h\"\n#include \"soaUtils.h\"\n\n#include <Vorb/utils.h>\n\n// TODO(Ben): This is temporary for gravity\n#define FPS 60.0\n// Exit is slightly bigger to prevent oscillation\n#define ENTRY_RADIUS_MULT 1.02\n#define EXIT_RADIUS_MULT 1.0205\n\n// TODO(Ben): Timestep\nvoid PhysicsComponentUpdater::update(GameSystem* gameSystem, SpaceSystem* spaceSystem) {\n  \n    for (auto& it : gameSystem->physics) {\n        auto& cmp = it.second;\n        // Voxel position dictates space position\n        if (cmp.voxelPosition) {\n            updateVoxelPhysics(gameSystem, spaceSystem, cmp, it.first);\n        } else {\n            updateSpacePhysics(gameSystem, spaceSystem, cmp, it.first);\n        } \n    }\n}\n\nf64v3 PhysicsComponentUpdater::calculateGravityAcceleration(f64v3 relativePosition, f64 mass) {\n    f64 dist2 = glm::dot(relativePosition, relativePosition); // Get distance^2\n    relativePosition /= sqrt(dist2); // Normalize position\n    f64 fgrav = M_G * mass / (dist2 * M_PER_KM * M_PER_KM); // Calculate force\n    return relativePosition * ((fgrav / M_PER_KM) / FPS); // Return acceleration vector\n}\n\n// TODO(Ben): This is a clusterfuck\nvoid PhysicsComponentUpdater::updateVoxelPhysics(GameSystem* gameSystem, SpaceSystem* spaceSystem,\n                                                 PhysicsComponent& pyCmp, vecs::EntityID entity) {\n\n    // Get the position component\n    auto& spCmp = gameSystem->spacePosition.get(pyCmp.spacePosition);\n    // Check for removal of spherical voxel component\n    auto& stCmp = spaceSystem->sphericalTerrain.get(spCmp.parentSphericalTerrain);\n    if (stCmp.sphericalVoxelComponent == 0) {\n        // We need to transition to space\n        pyCmp.voxelPosition = 0;\n        // TODO(Ben): Orient this\n        pyCmp.velocity = f64v3(0.0);\n        GameSystemAssemblages::removeVoxelPosition(gameSystem, entity);\n        GameSystemAssemblages::removeChunkSphere(gameSystem, entity);\n        return;\n    }\n\n    auto& vpcmp = gameSystem->voxelPosition.get(pyCmp.voxelPosition);\n    auto& svcmp = spaceSystem->sphericalVoxel.get(vpcmp.parentVoxel);\n    // auto& npcmp = spaceSystem->namePosition.get(svcmp.namePositionComponent);\n    auto& arcmp = spaceSystem->axisRotation.get(svcmp.axisRotationComponent);\n\n    // Apply gravity\n    if (spCmp.parentGravity) {\n        auto& gravCmp = spaceSystem->sphericalGravity.get(spCmp.parentGravity);\n        f64 height = (vpcmp.gridPosition.pos.y + svcmp.voxelRadius) * M_PER_VOXEL;\n        f64 fgrav = M_G * gravCmp.mass / (height * height);\n        ChunkID id(VoxelSpaceConversions::voxelToChunk(vpcmp.gridPosition));\n        ChunkHandle chunk = svcmp.chunkGrids[vpcmp.gridPosition.face].accessor.acquire(id);\n        // Don't apply gravity in non generated chunks.\n        if (chunk->genLevel == GEN_DONE) {\n            pyCmp.velocity.y -= (fgrav * 0.1) / FPS;\n        }\n        chunk.release();\n    }\n    // Update position\n    vpcmp.gridPosition.pos += pyCmp.velocity;\n    // Store old position in case of transition\n    VoxelPositionComponent oldVPCmp = vpcmp;\n    SpacePositionComponent oldSPCmp = spCmp;\n\n    // Check transition to new face\n    bool didTransition = false;\n    if (vpcmp.gridPosition.pos.x < -svcmp.voxelRadius) {\n        didTransition = true;\n        transitionNegX(vpcmp, pyCmp, (f32)svcmp.voxelRadius);\n    } else if (vpcmp.gridPosition.pos.x > svcmp.voxelRadius) {\n        didTransition = true;\n        transitionPosX(vpcmp, pyCmp, (f32)svcmp.voxelRadius);\n    } else if (vpcmp.gridPosition.pos.z < -svcmp.voxelRadius) {\n        didTransition = true;\n        transitionNegZ(vpcmp, pyCmp, (f32)svcmp.voxelRadius);\n    } else if (vpcmp.gridPosition.pos.z > svcmp.voxelRadius) {\n        didTransition = true;\n        transitionPosZ(vpcmp, pyCmp, (f32)svcmp.voxelRadius);\n    }\n\n    // Compute the relative space position and orientation from voxel position and orientation\n    spCmp.position = arcmp.currentOrientation * VoxelSpaceConversions::voxelToWorld(vpcmp.gridPosition, svcmp.voxelRadius) * KM_PER_VOXEL;\n\n    // TODO(Ben): This is expensive as fuck. Make sure you only do this for components that actually need it\n    spCmp.orientation = arcmp.currentOrientation * VoxelSpaceUtils::calculateVoxelToSpaceQuat(vpcmp.gridPosition, svcmp.voxelRadius) * vpcmp.orientation;\n\n    // Check transitions\n    // TODO(Ben): This assumes a single player entity!\n    if (spCmp.parentSphericalTerrain) {\n        auto& stCmp = spaceSystem->sphericalTerrain.get(spCmp.parentSphericalTerrain);\n\n        f64 distance = glm::length(spCmp.position);\n        // Check transition to Space\n        if (distance > stCmp.sphericalTerrainData->radius * EXIT_RADIUS_MULT) {\n            if (stCmp.needsVoxelComponent) {\n                stCmp.needsVoxelComponent = false;\n                // Begin fade transition\n                stCmp.alpha = TERRAIN_INC_START_ALPHA;\n            }\n        } else if (didTransition) { // Check face transition\n            // Check face-to-face transition cases\n            if (stCmp.transitionFace == FACE_NONE && !stCmp.isFaceTransitioning) {\n                stCmp.transitionFace = vpcmp.gridPosition.face;\n                stCmp.isFaceTransitioning = true;\n                vpcmp = oldVPCmp;\n                spCmp = oldSPCmp;\n            } else if (stCmp.isFaceTransitioning) {\n                // Check for transition end\n                if (stCmp.faceTransTime < 0.2f) {\n                    stCmp.isFaceTransitioning = false;\n                } else {\n                    vpcmp = oldVPCmp;\n                    spCmp = oldSPCmp;\n                }\n            }\n        }\n    } else {\n        // This really shouldn't happen\n        std::cerr << \"Missing parent spherical terrain ID in updateVoxelPhysics\\n\";\n    }\n}\n\nvoid PhysicsComponentUpdater::updateSpacePhysics(GameSystem* gameSystem, SpaceSystem* spaceSystem,\n                                                 PhysicsComponent& pyCmp, vecs::EntityID entity) {\n\n    // Get the position component\n    auto& spCmp = gameSystem->spacePosition.get(pyCmp.spacePosition);\n\n    // Apply gravity\n    // TODO(Ben): Optimize and fix with timestep\n    if (spCmp.parentGravity) {\n        auto& gravCmp = spaceSystem->sphericalGravity.get(spCmp.parentGravity);\n        pyCmp.velocity += calculateGravityAcceleration(-spCmp.position, gravCmp.mass);\n    } else {\n        // TODO(Ben): Check gravity on all planets? check transition to parent?\n    }\n\n    // Update position\n    spCmp.position += pyCmp.velocity; // * timestep\n\n    // Check transition to planet\n    // TODO(Ben): This assumes a single player entity!\n    if (spCmp.parentSphericalTerrain) {\n        auto& stCmp = spaceSystem->sphericalTerrain.get(spCmp.parentSphericalTerrain);\n        // auto& npCmp = spaceSystem->namePosition.get(stCmp.namePositionComponent);\n\n        f64 distance = glm::length(spCmp.position);\n        if (distance <= stCmp.sphericalTerrainData->radius * ENTRY_RADIUS_MULT) {\n            // Mark the terrain component as needing voxels\n            if (!stCmp.needsVoxelComponent) {\n                auto& arCmp = spaceSystem->axisRotation.getFromEntity(stCmp.axisRotationComponent);\n                stCmp.startVoxelPosition = VoxelSpaceConversions::worldToVoxel(arCmp.invCurrentOrientation * spCmp.position * VOXELS_PER_KM,\n                                                                               stCmp.sphericalTerrainData->radius * VOXELS_PER_KM);\n                stCmp.needsVoxelComponent = true;\n                // Start the fade transition\n                stCmp.alpha = TERRAIN_DEC_START_ALPHA;\n            } else if (!pyCmp.voxelPosition && stCmp.sphericalVoxelComponent) { // Check if we need to create the voxelPosition component\n\n                auto& arCmp = spaceSystem->axisRotation.getFromEntity(stCmp.axisRotationComponent);\n                // Calculate voxel relative orientation\n                f64q voxOrientation = glm::inverse(VoxelSpaceUtils::calculateVoxelToSpaceQuat(stCmp.startVoxelPosition,\n                    stCmp.sphericalTerrainData->radius * VOXELS_PER_KM)) * arCmp.invCurrentOrientation * spCmp.orientation;\n\n                // Make the voxel position component\n                vecs::ComponentID vpid = GameSystemAssemblages::addVoxelPosition(gameSystem, entity,\n                                                                                  stCmp.sphericalVoxelComponent,\n                                                                                  voxOrientation,\n                                                                                  stCmp.startVoxelPosition);\n                \n                // Make the Chunk Sphere component\n                GameSystemAssemblages::addChunkSphere(gameSystem, entity, vpid, VoxelSpaceConversions::voxelToChunk(stCmp.startVoxelPosition), 7);\n                \n                auto& hcmp = gameSystem->head.getFromEntity(entity);\n                hcmp.voxelPosition = vpid;\n                pyCmp.voxelPosition = vpid;\n\n                // TODO(Ben): Calculate velocity change properly\n                //pyCmp.velocity = voxOrientation * pyCmp.velocity;\n                pyCmp.velocity = f64v3(0); // VOXELS_PER_KM;\n\n                // Update dependencies for frustum\n                gameSystem->frustum.getFromEntity(entity).voxelPosition = vpid;\n            }\n        }\n    }\n}\n\n#define VOXEL_PUSH CHUNK_WIDTH\n\nvoid PhysicsComponentUpdater::transitionPosX(VoxelPositionComponent& vpCmp, PhysicsComponent& pyCmp VORB_MAYBE_UNUSED, float voxelRadius) {\n    // Push in by a chunk\n    float rad = voxelRadius - VOXEL_PUSH;\n    // We could use lookup tables for this, but this is easier\n    switch (vpCmp.gridPosition.face) {\n        case FACE_TOP:\n            vpCmp.orientation = f64q(f64v3(0.0, -M_PI / 2.0, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_RIGHT;\n            vpCmp.gridPosition.pos.x = -vpCmp.gridPosition.pos.z;\n            vpCmp.gridPosition.pos.z = -rad;\n            break;\n        case FACE_LEFT:\n            vpCmp.gridPosition.face = FACE_FRONT;\n            vpCmp.gridPosition.pos.x = -rad;\n            break;\n        case FACE_RIGHT:\n            vpCmp.gridPosition.face = FACE_BACK;\n            vpCmp.gridPosition.pos.x = -rad;\n            break;\n        case FACE_FRONT:\n            vpCmp.gridPosition.face = FACE_RIGHT;\n            vpCmp.gridPosition.pos.x = -rad;\n            break;\n        case FACE_BACK:\n            vpCmp.gridPosition.face = FACE_LEFT;\n            vpCmp.gridPosition.pos.x = -rad;\n            break;\n        case FACE_BOTTOM:\n            vpCmp.orientation = f64q(f64v3(0.0, M_PI / 2.0, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_RIGHT;\n            vpCmp.gridPosition.pos.x = vpCmp.gridPosition.pos.z;\n            vpCmp.gridPosition.pos.z = rad;\n            break;\n        default:\n            std::cerr << \"Invalid face in PhysicsComponentUpdater::transitionPosX\\n\";\n            break;\n    }\n}\n\nvoid PhysicsComponentUpdater::transitionNegX(VoxelPositionComponent& vpCmp, PhysicsComponent& pyCmp VORB_MAYBE_UNUSED, float voxelRadius) {\n    // Push in by a chunk\n    float rad = voxelRadius - VOXEL_PUSH;\n    // We could use lookup tables for this, but this is easier\n    switch (vpCmp.gridPosition.face) {\n        case FACE_TOP:\n            vpCmp.orientation = f64q(f64v3(0.0, M_PI / 2.0, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_LEFT;\n            vpCmp.gridPosition.pos.x = vpCmp.gridPosition.pos.z;\n            vpCmp.gridPosition.pos.z = -rad;\n            break;\n        case FACE_LEFT:\n            vpCmp.gridPosition.face = FACE_BACK;\n            vpCmp.gridPosition.pos.x = rad;\n            break;\n        case FACE_RIGHT:\n            vpCmp.gridPosition.face = FACE_FRONT;\n            vpCmp.gridPosition.pos.x = rad;\n            break;\n        case FACE_FRONT:\n            vpCmp.gridPosition.face = FACE_LEFT;\n            vpCmp.gridPosition.pos.x = rad;\n            break;\n        case FACE_BACK:\n            vpCmp.gridPosition.face = FACE_RIGHT;\n            vpCmp.gridPosition.pos.x = rad;\n            break;\n        case FACE_BOTTOM:\n            vpCmp.orientation = f64q(f64v3(0.0, -M_PI / 2.0, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_LEFT;\n            vpCmp.gridPosition.pos.x = -vpCmp.gridPosition.pos.z;\n            vpCmp.gridPosition.pos.z = rad;\n            break;\n        default:\n            std::cerr << \"Invalid face in PhysicsComponentUpdater::transitionPosX\\n\";\n            break;\n    }\n}\n\nvoid PhysicsComponentUpdater::transitionPosZ(VoxelPositionComponent& vpCmp, PhysicsComponent& pyCmp VORB_MAYBE_UNUSED, float voxelRadius) {\n    // Push in by a chunk\n    float rad = voxelRadius - VOXEL_PUSH;\n    // We could use lookup tables for this, but this is easier\n    switch (vpCmp.gridPosition.face) {\n        case FACE_TOP:\n            vpCmp.gridPosition.face = FACE_FRONT;\n            vpCmp.gridPosition.pos.z = -rad;\n            break;\n        case FACE_LEFT:\n            vpCmp.orientation = f64q(f64v3(0.0, M_PI / 2.0, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_BOTTOM;\n            vpCmp.gridPosition.pos.z = -vpCmp.gridPosition.pos.x;\n            vpCmp.gridPosition.pos.x = -rad;\n            break;\n        case FACE_RIGHT:\n            vpCmp.orientation = f64q(f64v3(0.0, -M_PI / 2.0, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_BOTTOM;\n            vpCmp.gridPosition.pos.z = vpCmp.gridPosition.pos.x;\n            vpCmp.gridPosition.pos.x = rad;\n            break;\n        case FACE_FRONT:\n            vpCmp.gridPosition.face = FACE_BOTTOM;\n            vpCmp.gridPosition.pos.z = -rad;\n            break;\n        case FACE_BACK:\n            vpCmp.orientation = f64q(f64v3(0.0, M_PI, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_BOTTOM;\n            vpCmp.gridPosition.pos.z = -rad;\n            vpCmp.gridPosition.pos.x = -vpCmp.gridPosition.pos.x;\n            break;\n        case FACE_BOTTOM:\n            vpCmp.orientation = f64q(f64v3(0.0, M_PI, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_BACK;\n            vpCmp.gridPosition.pos.z = -rad;\n            vpCmp.gridPosition.pos.x = -vpCmp.gridPosition.pos.x;\n            break;\n        default:\n            std::cerr << \"Invalid face in PhysicsComponentUpdater::transitionPosX\\n\";\n            break;\n    }\n}\n\nvoid PhysicsComponentUpdater::transitionNegZ(VoxelPositionComponent& vpCmp, PhysicsComponent& pyCmp VORB_MAYBE_UNUSED, float voxelRadius) {\n    // Push in by a chunk\n    float rad = voxelRadius - VOXEL_PUSH;\n    // We could use lookup tables for this, but this is easier\n    switch (vpCmp.gridPosition.face) {\n        case FACE_TOP:\n            vpCmp.orientation = f64q(f64v3(0.0, M_PI, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_BACK;\n            vpCmp.gridPosition.pos.z = -rad;\n            vpCmp.gridPosition.pos.x = -vpCmp.gridPosition.pos.x;\n            break;\n        case FACE_LEFT:\n            vpCmp.orientation = f64q(f64v3(0.0, -M_PI / 2.0, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_TOP;\n            vpCmp.gridPosition.pos.z = vpCmp.gridPosition.pos.x;\n            vpCmp.gridPosition.pos.x = -rad;\n            break;\n        case FACE_RIGHT:\n            vpCmp.orientation = f64q(f64v3(0.0, M_PI / 2.0, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_TOP;\n            vpCmp.gridPosition.pos.z = -vpCmp.gridPosition.pos.x;\n            vpCmp.gridPosition.pos.x = rad;\n            break;\n        case FACE_FRONT:\n            vpCmp.gridPosition.face = FACE_TOP;\n            vpCmp.gridPosition.pos.z = rad;\n            break;\n        case FACE_BACK:\n            vpCmp.orientation = f64q(f64v3(0.0, M_PI, 0.0)) * vpCmp.orientation;\n            vpCmp.gridPosition.face = FACE_TOP;\n            vpCmp.gridPosition.pos.z = -rad;\n            vpCmp.gridPosition.pos.x = -vpCmp.gridPosition.pos.x;\n            break;\n        case FACE_BOTTOM:\n            vpCmp.gridPosition.face = FACE_FRONT;\n            vpCmp.gridPosition.pos.z = rad;\n            break;\n        default:\n            std::cerr << \"Invalid face in PhysicsComponentUpdater::transitionPosX\\n\";\n            break;\n    }\n}\n\n#undef VOXEL_PUSH"
  },
  {
    "path": "SoA/PhysicsComponentUpdater.h",
    "content": "///\n/// PhysicsComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates physics components\n///\n\n#pragma once\n\n#ifndef PhysicsComponentUpdater_h__\n#define PhysicsComponentUpdater_h__\n\nclass GameSystem;\nclass SpaceSystem;\nstruct PhysicsComponent;\nstruct VoxelPositionComponent;\n\n#include <Vorb/ecs/ECS.h>\n\n// TODO(Ben): Timestep\nclass PhysicsComponentUpdater {\npublic:\n    /// Updates physics components\n    /// @param gameSystem: Game ECS\n    /// @param spaceSystem: Space ECS.\n    void update(GameSystem* gameSystem, SpaceSystem* spaceSystem);\n\n    /// Calculates the acceleration vector due to gravity\n    /// @relativePosition: Relative position of object to attractor\n    /// @mass: Mass of the attractor\n    /// @return the acceleration vector\n    static f64v3 calculateGravityAcceleration(f64v3 relativePosition, f64 mass);\nprivate:\n    void updateVoxelPhysics(GameSystem* gameSystem, SpaceSystem* spaceSystem,\n                            PhysicsComponent& pyCmp, vecs::EntityID entity);\n    void updateSpacePhysics(GameSystem* gameSystem, SpaceSystem* spaceSystem,\n                            PhysicsComponent& pyCmp, vecs::EntityID entity);\n    void transitionPosX(VoxelPositionComponent& vpCmp, PhysicsComponent& pyCmp, float voxelRadius);\n    void transitionNegX(VoxelPositionComponent& vpCmp, PhysicsComponent& pyCmp, float voxelRadius);\n    void transitionPosZ(VoxelPositionComponent& vpCmp, PhysicsComponent& pyCmp, float voxelRadius);\n    void transitionNegZ(VoxelPositionComponent& vpCmp, PhysicsComponent& pyCmp, float voxelRadius);\n    \n};\n\n#endif // PhysicsComponentUpdater_h__\n"
  },
  {
    "path": "SoA/Planet.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Planet.h\"\n\n#include <glm\\gtc\\type_ptr.hpp>\n#include <glm\\gtc\\quaternion.hpp>\n#include <glm\\gtx\\quaternion.hpp>\n#include <glm\\gtc\\matrix_transform.hpp>\n#include <Vorb/graphics/GLStates.h>\n\n#include \"Camera.h\"\n//#include \"FileSystem.h\"\n#include \"GameManager.h\"\n//#include \"InputManager.h\"\n#include \"Inputs.h\"\n//#include \"ObjectLoader.h\"\n//#include \"Options.h\"\n//#include \"Rendering.h\"\n//#include \"TerrainGenerator.h\"\n//#include \"TerrainPatch.h\"\n//#include \"TexturePackLoader.h\"\n\n\n//ObjectLoader objectLoader;\n\nPlanet::Planet()\n{\n    bindex = 0;\n    stormNoiseFunction = NULL;\n    sunnyCloudyNoiseFunction = NULL;\n    cumulusNoiseFunction = NULL;\n    rotationTheta = 0;\n    rotationMatrix = glm::mat4(1.0);\n    invRotationMatrix = glm::inverse(rotationMatrix);\n    axialZTilt = 0.4;\n    baseTemperature = 100;\n    baseRainfall = 100;\n    minHumidity = 0.0f;\n    maxHumidity = 100.0f;\n    minCelsius = -20.0f;\n    maxCelsius = 60.0f;\n    solarX = solarY = solarZ = 0;\n    scaledRadius = 0;\n    gravityConstant = 1.0;\n    density = 1.0;\n}\n\nPlanet::~Planet()\n{\n    destroy();\n}\n\nvoid Planet::clearMeshes()\n{\n//    TerrainBuffers *tb;\n//    for (int k = 0; k < 6; k++){\n//        for (size_t i = 0; i < drawList[k].size(); i++){\n//            tb = drawList[k][i];\n//            if (tb->vaoID != 0) glDeleteVertexArrays(1, &(tb->vaoID));\n//            if (tb->vboID != 0) glDeleteBuffers(1, &(tb->vboID));\n//            if (tb->treeVboID != 0) glDeleteBuffers(1, &(tb->treeVboID));\n//            if (tb->vboIndexID != 0) glDeleteBuffers(1, &(tb->vboIndexID));\n//            delete tb;\n//        }\n//\n//        drawList[k].clear();\n//    }\n\n\n//    for (size_t i = 0; i < 6U; i++){\n//        for (size_t j = 0; j < faces[i].size(); j++){\n//            for (size_t k = 0; k < faces[i][j].size(); k++){\n//                faces[i][j][k]->NullifyBuffers();\n//            }\n//        }\n//    }\n}\n\nvoid Planet::initialize(nString filePath)\n{\n    #define MAP_WIDTH 256\n    #define DEFAULT_RADIUS 1000000\n    if (filePath == \"Worlds/(Empty Planet)/\"){\n        radius = DEFAULT_RADIUS;\n        scaledRadius = (radius - radius%CHUNK_WIDTH) / planetScale;\n        int width = scaledRadius / TerrainPatchWidth * 2;\n        if (width % 2 == 0){ // must be odd\n            width++;\n        }\n        scaledRadius = (width*TerrainPatchWidth) / 2;\n        radius = (int)(scaledRadius*planetScale);\n        ColorRGB8* colorMap = GameManager::texturePackLoader->getColorMap(\"biome\");\n        ColorRGB8* waterColorMap = GameManager::texturePackLoader->getColorMap(\"water\");\n\n        for (int i = 0; i < MAP_WIDTH * MAP_WIDTH; i++){\n            colorMap[i] = ColorRGB8(0, 255, 0);\n        }\n\n        for (int i = 0; i < MAP_WIDTH * MAP_WIDTH; i++){\n            colorMap[i] = ColorRGB8(0, 0, 255);\n        }\n\n        for (int i = 0; i < 256; i++){\n            for (int j = 0; j < 256; j++){\n                int hexcode = 0;\n                GameManager::terrainGenerator->BiomeMap[i][j] = hexcode;\n            }\n        }\n\n        atmosphere.initialize(\"\", scaledRadius);\n    }\n    else{\n        loadData(filePath, 0);\n\n\n        atmosphere.initialize(filePath + \"Sky/properties.ini\", scaledRadius);\n    }\n    dirName = filePath;\n\n    rotationTheta = 0;\n    glm::vec3 EulerAngles(0, rotationTheta, axialZTilt);\n    rotateQuaternion = glm::quat(EulerAngles);\n    rotationMatrix = glm::toMat4(rotateQuaternion);\n\n    double mrad = (double)radius / 2.0;\n    volume = (4.0 / 3.0)*M_PI*mrad*mrad*mrad;\n    mass = volume*density;\n\n    facecsGridWidth = (radius * 2) / CHUNK_WIDTH;\n}\n\nvoid Planet::initializeTerrain(const glm::dvec3 &startPosition)\n{\n    int lodx, lody, lodz;\n\n    int wx = (int)startPosition.x, wy = (int)startPosition.y, wz = (int)startPosition.z;\n    int width = scaledRadius/TerrainPatchWidth*2;\n    if (width%2 == 0){ // must be odd\n        width++;\n    }\n    std::cout << \"RADIUS \" << radius << \" Width \" << width << std::endl;\n    std::cout << \"XYZ \" << solarX << \" \" << solarY << \" \" << solarZ << std::endl;\n\n    int centerX = 0;\n    int centerY = 0 + scaledRadius;\n    int centerZ = 0;\n    double magnitude;\n\n    faces[P_TOP].resize(width);\n    for (size_t i = 0; i < faces[P_TOP].size(); i++){\n        faces[P_TOP][i].resize(width);\n        for (size_t j = 0; j < faces[P_TOP][i].size(); j++){\n            faces[P_TOP][i][j] = new TerrainPatch(TerrainPatchWidth);\n\n            lodx = 0 + (j - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            lody = centerY;\n            lodz = 0 + (i - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            magnitude = sqrt(lodx*lodx + lody*lody + lodz*lodz);\n\n            faces[P_TOP][i][j]->Initialize(lodx, lody, lodz, wx, wy, wz, radius, P_TOP);\n            while(!(faces[P_TOP][i][j]->CreateMesh())); //load all of the quadtrees\n        }\n    }\n\n    centerX = 0 - scaledRadius;\n    centerY = 0;\n    centerZ = 0;\n    faces[P_LEFT].resize(width);\n    for (size_t i = 0; i < faces[P_LEFT].size(); i++){\n        faces[P_LEFT][i].resize(width);\n        for (size_t j = 0; j < faces[P_LEFT][i].size(); j++){\n            faces[P_LEFT][i][j] = new TerrainPatch(TerrainPatchWidth);\n\n            lodx = centerX;\n            lody = 0 + (i - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            lodz = 0 + (j - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            magnitude = sqrt(lodx*lodx + lody*lody + lodz*lodz);\n\n            faces[P_LEFT][i][j]->Initialize(lodx, lody, lodz, wx, wy, wz, radius, P_LEFT);\n            while(!(faces[P_LEFT][i][j]->CreateMesh())); //load all of the quadtrees\n        }\n    }\n\n    centerX = 0 + scaledRadius;\n    centerY = 0;\n    centerZ = 0;\n    faces[P_RIGHT].resize(width);\n    for (size_t i = 0; i < faces[P_RIGHT].size(); i++){\n        faces[P_RIGHT][i].resize(width);\n        for (size_t j = 0; j < faces[P_RIGHT][i].size(); j++){\n            faces[P_RIGHT][i][j] = new TerrainPatch(TerrainPatchWidth);\n\n            lodx = centerX;\n            lody = 0 + (i - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            lodz = 0 + (j - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            magnitude = sqrt(lodx*lodx + lody*lody + lodz*lodz);\n\n            faces[P_RIGHT][i][j]->Initialize(lodx, lody, lodz, wx, wy, wz, radius, P_RIGHT);\n\n            while(!(faces[P_RIGHT][i][j]->CreateMesh())); //load all of the quadtrees\n        }\n    }\n\n    centerX = 0;\n    centerY = 0;\n    centerZ = 0 + scaledRadius;\n    faces[P_FRONT].resize(width);\n    for (size_t i = 0; i < faces[P_FRONT].size(); i++){\n        faces[P_FRONT][i].resize(width);\n        for (size_t j = 0; j < faces[P_FRONT][i].size(); j++){\n            faces[P_FRONT][i][j] = new TerrainPatch(TerrainPatchWidth);\n\n            lodx = 0 + (j - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            lody = 0 + (i - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            lodz = centerZ;\n            magnitude = sqrt(lodx*lodx + lody*lody + lodz*lodz);\n\n\n            //TopFace[i][j]->Initialize(((double)lodx/magnitude)*radius, ((double)lody/magnitude)*radius, ((double)lodz/magnitude)*radius, centerX, centerY, centerZ);\n            faces[P_FRONT][i][j]->Initialize(lodx, lody, lodz, wx, wy, wz, radius, P_FRONT);\n\n            while(!(faces[P_FRONT][i][j]->CreateMesh())); //load all of the quadtrees\n        }\n    }\n\n    centerX = 0;\n    centerY = 0;\n    centerZ = 0 - scaledRadius;\n    faces[P_BACK].resize(width);\n    for (size_t i = 0; i < faces[P_BACK].size(); i++){\n        faces[P_BACK][i].resize(width);\n        for (size_t j = 0; j < faces[P_BACK][i].size(); j++){\n            faces[P_BACK][i][j] = new TerrainPatch(TerrainPatchWidth);\n\n            lodx = 0 + (j - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            lody = 0 + (i - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            lodz = centerZ;\n            magnitude = sqrt(lodx*lodx + lody*lody + lodz*lodz);\n\n            faces[P_BACK][i][j]->Initialize(lodx, lody, lodz, wx, wy, wz, radius, P_BACK);\n\n            while(!(faces[P_BACK][i][j]->CreateMesh())); //load all of the quadtrees\n        }\n    }\n\n    centerX = 0;\n    centerY = 0 - scaledRadius;\n    centerZ = 0;\n\n    faces[P_BOTTOM].resize(width);\n    for (size_t i = 0; i < faces[P_BOTTOM].size(); i++){\n        printf(\"%d \", i);\n        faces[P_BOTTOM][i].resize(width);\n        for (size_t j = 0; j < faces[P_BOTTOM][i].size(); j++){\n            faces[P_BOTTOM][i][j] = new TerrainPatch(TerrainPatchWidth);\n\n            lodx = 0 + (j - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            lody = centerY;\n            lodz = 0 + (i - width/2) * TerrainPatchWidth - TerrainPatchWidth/2;\n            magnitude = sqrt(lodx*lodx + lody*lody + lodz*lodz);\n\n            faces[P_BOTTOM][i][j]->Initialize(lodx, lody, lodz, wx, wy, wz, radius, P_BOTTOM);\n\n            while(!(faces[P_BOTTOM][i][j]->CreateMesh())); //load all of the quadtrees\n        }\n    }\n}\n\nvoid Planet::loadData(nString filePath, bool ignoreBiomes)\n{    \n\n    loadProperties(filePath + \"properties.ini\");\n    saveProperties(filePath + \"properties.ini\"); //save em to update them\n\n\n    TerrainGenerator* generator = GameManager::terrainGenerator;\n\n    GameManager::planet = this;\n    vg::TextureCache* textureCache = GameManager::textureCache;\n    if (!ignoreBiomes){\n        if (fileManager.loadNoiseFunctions((filePath + \"Noise/TerrainNoise.SOANOISE\").c_str(), 0, this)) {\n            pError(\"Failed to load terrain noise functions!\");\n            exit(75);\n        }\n        if (fileManager.loadNoiseFunctions((filePath + \"Noise/MandatoryNoise.SOANOISE\").c_str(), 1, this)) {\n            pError(\"Failed to load mandatory noise functions!\");\n            exit(76);\n        }\n    }\n    \n    if (fileManager.loadFloraData(this, filePath)) {\n        pError(\"Failed to load flora data!\");\n        exit(77);\n    }\n    if (fileManager.loadAllTreeData(this, filePath)) {\n        pError(\"Failed to load tree data\");\n        exit(78);\n    }\n    if (!ignoreBiomes){\n        if (fileManager.loadBiomeData(this, filePath)) {\n            pError(\"Failed to load biome data!\");\n            exit(79);\n        }\n    }\n\n    //Uncomment to save all trees after loading, for file conversions\n     /*for (size_t i = 0; i < treeTypeVec.size(); i++){\n        fileManager.SaveTreeData(treeTypeVec[i]);\n    }*/\n\n    fileManager.saveBiomeData(this, filePath);\n    \n    sunColorMapTexture = textureCache->addTexture(filePath + \"/Sky/sunColor.png\", &SamplerState::LINEAR_CLAMP_MIPMAP);\n\n#define MAP_WIDTH 256\n\n    GLubyte buffer[MAP_WIDTH * MAP_WIDTH][3];\n    if (!ignoreBiomes){\n        glActiveTexture(GL_TEXTURE8);\n        glBindTexture(GL_TEXTURE_2D, GameManager::planet->biomeMapTexture.id);\n        \n        glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, buffer);\n\n        //convert rgb values into a hex int\n        for (int i = 0; i < MAP_WIDTH; i++){\n            for (int j = 0; j < MAP_WIDTH; j++){\n                int hexcode = 0;\n                hexcode |= (((int)buffer[i * MAP_WIDTH + j][2]) << 16); //converts bgr to rgb\n                hexcode |= (((int)buffer[i * MAP_WIDTH + j][1]) << 8);\n                hexcode |= ((int)buffer[i * MAP_WIDTH + j][0]);\n                generator->BiomeMap[i][j] = hexcode;\n            }\n        }\n    }\n\n    ColorRGB8* biomeMap = GameManager::texturePackLoader->getColorMap(\"biome\");\n    ColorRGB8* waterMap = GameManager::texturePackLoader->getColorMap(\"water\");\n\n    //color map!\n    glBindTexture(GL_TEXTURE_2D, GameManager::planet->colorMapTexture.id);\n    glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, buffer);\n    for (int y = 0; y < MAP_WIDTH; y++){\n        for (int x = 0; x < MAP_WIDTH; x++) {\n            biomeMap[(MAP_WIDTH - y - 1) * MAP_WIDTH + x] = ColorRGB8(buffer[y * MAP_WIDTH + x][2], //convert bgr to rgb\n                                                                      buffer[y * MAP_WIDTH + x][1],\n                                                                      buffer[y * MAP_WIDTH + x][0]);\n        }\n    }\n\n    glBindTexture(GL_TEXTURE_2D, GameManager::planet->waterColorMapTexture.id);\n    glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, buffer);\n    for (int y = 0; y < MAP_WIDTH; y++){\n        for (int x = 0; x < MAP_WIDTH; x++) {\n            waterMap[(MAP_WIDTH - y - 1) * MAP_WIDTH + x] = ColorRGB8(buffer[y * MAP_WIDTH + x][2], //convert bgr to rgb\n                                                                      buffer[y * MAP_WIDTH + x][1],\n                                                                      buffer[y * MAP_WIDTH + x][0]);\n        }\n    }\n    \n}\n\nvoid Planet::saveProperties(nString filePath)\n{\n    std::vector <std::vector <IniValue> > iniValues;\n    std::vector <nString> iniSections;\n\n    iniSections.push_back(\"\");\n    iniValues.push_back(std::vector<IniValue>());\n    iniSections.push_back(\"Properties\");\n    iniValues.push_back(std::vector<IniValue>());\n    iniValues.back().push_back(IniValue(\"x\", 0));\n    iniValues.back().push_back(IniValue(\"y\", 0));\n    iniValues.back().push_back(IniValue(\"z\", 0));\n    iniValues.back().push_back(IniValue(\"radius\", radius));\n    iniValues.back().push_back(IniValue(\"gravityConstant\", gravityConstant));\n    iniValues.back().push_back(IniValue(\"density\", density));\n    iniValues.back().push_back(IniValue(\"axialTilt\", axialZTilt));\n    iniSections.push_back(\"Climate\");\n    iniValues.push_back(std::vector<IniValue>());\n    iniValues.back().push_back(IniValue(\"baseTemperature\", baseTemperature));\n    iniValues.back().push_back(IniValue(\"minCelsius\", minCelsius));\n    iniValues.back().push_back(IniValue(\"maxCelsius\", maxCelsius));\n    iniValues.back().push_back(IniValue(\"baseHumidity\", baseRainfall));\n    iniValues.back().push_back(IniValue(\"minHumidity\", minHumidity));\n    iniValues.back().push_back(IniValue(\"maxHumidity\", maxHumidity));\n    \n    fileManager.saveIniFile(filePath, iniValues, iniSections);\n}\n\nvoid Planet::loadProperties(nString filePath)\n{\n    std::vector < std::vector <IniValue> > iniValues;\n    std::vector <nString> iniSections;\n    fileManager.loadIniFile(filePath, iniValues, iniSections);\n\n    int iVal;\n    IniValue *iniVal;\n    for (size_t i = 0; i < iniSections.size(); i++){\n        for (size_t j = 0; j < iniValues[i].size(); j++){\n            iniVal = &(iniValues[i][j]);\n\n            iVal = fileManager.getIniVal(iniVal->key);\n            switch (iVal){\n            case INI_X:\n                solarX = iniVal->getInt();\n                break;\n            case INI_Y:\n                solarY = iniVal->getInt();\n                break;\n            case INI_Z:\n                solarZ = iniVal->getInt();\n                break;\n            case INI_DENSITY:\n                density = iniVal->getFloat();\n                break;\n            case INI_GRAVITYCONSTANT:\n                gravityConstant = iniVal->getFloat();\n                break;\n            case INI_BASETEMPERATURE:\n                baseTemperature = iniVal->getInt();\n                break;\n            case INI_BASEHUMIDITY:\n                baseRainfall = iniVal->getInt();\n                break;\n            case INI_AXIALTILT:\n                axialZTilt = iniVal->getFloat();\n                break;\n            case INI_MINCELSIUS:\n                minCelsius = iniVal->getFloat();\n                break;\n            case INI_MAXCELSIUS:\n                maxCelsius = iniVal->getFloat();\n                break;\n            case INI_MINHUMIDITY:\n                minHumidity = iniVal->getFloat();\n                break;\n            case INI_MAXHUMIDITY:\n                maxHumidity = iniVal->getFloat();\n                break;\n            case INI_RADIUS:\n                radius = iniVal->getFloat();\n                scaledRadius = (radius - radius%CHUNK_WIDTH) / planetScale;\n                int width = scaledRadius / TerrainPatchWidth * 2;\n                if (width % 2 == 0){ // must be odd\n                    width++;\n                }\n                scaledRadius = (width*TerrainPatchWidth) / 2;\n                radius = (int)(scaledRadius*planetScale);\n                break;\n            }\n        }\n    }\n}\n\nvoid Planet::saveData()\n{\n    fileManager.saveBiomeData(this, \"World/\");\n    fileManager.saveAllBiomes(this);\n}\n\nvoid Planet::rotationUpdate()\n{\n    float rotationInput = GameManager::inputManager->getAxis(INPUT_PLANET_ROTATION);\n    if (std::abs(rotationInput) > 0) {\n        rotationTheta += rotationInput * 0.01 * physSpeedFactor;\n    }else{\n        rotationTheta += 0.00002*physSpeedFactor;//0.00001\n    }\n    if (rotationTheta > 3.14){\n        rotationTheta = -3.14;\n    }else if (rotationTheta < -3.14){\n        rotationTheta = 3.14;\n    }\n\n    glm::vec3 EulerAngles(0, rotationTheta, axialZTilt);\n    rotateQuaternion = glm::quat(EulerAngles);\n    //gameToGl.enqueue(OMessage(GL_M_UPDATEPLANET, (void *)(new PlanetUpdateMessage(glm::toMat4(rotateQuaternion)))));\n    rotationMatrix = glm::toMat4(rotateQuaternion);\n    invRotationMatrix = glm::inverse(rotationMatrix);\n}\n\nvoid Planet::draw(float theta, const Camera* camera, glm::vec3 lightPos, GLfloat sunVal, float fadeDistance, bool connectedToPlanet)\n{    \n    \n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D, terrainTexture.id);\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, waterNormalTexture.id);\n    glActiveTexture(GL_TEXTURE2);\n    glBindTexture(GL_TEXTURE_2D, biomeMapTexture.id);\n    glActiveTexture(GL_TEXTURE3);\n    glBindTexture(GL_TEXTURE_2D, waterColorMapTexture.id);\n    glActiveTexture(GL_TEXTURE4);\n    glBindTexture(GL_TEXTURE_2D, waterNoiseTexture.id);\n\n    glActiveTexture(GL_TEXTURE6);\n    glBindTexture(GL_TEXTURE_2D, sunColorMapTexture.id);\n\n    glActiveTexture(GL_TEXTURE7);\n    glBindTexture(GL_TEXTURE_2D, colorMapTexture.id);\n\n    closestTerrainPatchDistance = 999999999999.0;\n\n    const f64v3& playerPos = camera->getPosition();\n\n    glm::dvec3 rotPlayerPos;\n    glm::dvec3 nPlayerPos;\n    glm::vec3 rotLightPos;\n    rotLightPos = glm::vec3((GameManager::planet->invRotationMatrix) * glm::vec4(lightPos, 1.0));\n    bool onPlanet;\n    if (connectedToPlanet){\n        rotPlayerPos = playerPos;\n        nPlayerPos = playerPos;\n        onPlanet = 1;\n    }else{\n        rotPlayerPos = glm::dvec3((glm::dmat4(GameManager::planet->invRotationMatrix)) * glm::dvec4(playerPos, 1.0));\n        nPlayerPos = playerPos;\n        onPlanet = 0;\n    }\n\n    f32m4 VP = camera->getProjectionMatrix() * camera->getViewMatrix();\n    drawGround(theta, camera, VP, rotLightPos, nPlayerPos, rotPlayerPos, fadeDistance, onPlanet);\n}\n\nvoid Planet::drawTrees(const glm::mat4 &VP, const glm::dvec3 &PlayerPos, GLfloat sunVal)\n{\n    glm::vec3 worldUp = glm::vec3(glm::normalize(PlayerPos));\n//    glDisable(GL_CULL_FACE);\n    vg::GLProgram* program = GameManager::glProgramManager->getProgram(\"TreeBillboard\");\n    program->use();\n    program->enableVertexAttribArrays();\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D, treeTrunkTexture1.id);\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, normalLeavesTexture.id);\n    glActiveTexture(GL_TEXTURE2);\n    glBindTexture(GL_TEXTURE_2D, pineLeavesTexture.id);\n    glActiveTexture(GL_TEXTURE3);\n    glBindTexture(GL_TEXTURE_2D, mushroomCapTexture.id);\n\n    glUniform3f(program->getUniform(\"worldUp\"), worldUp.x, worldUp.y, worldUp.z);\n    glUniform1f(program->getUniform(\"FadeDistance\"), (GLfloat)((csGridWidth / 2) * CHUNK_WIDTH)*invPlanetScale);\n    glUniform1f(program->getUniform(\"sunVal\"), sunVal);\n\n    for (size_t f = 0; f < 6; f++){\n        for (size_t i = 0; i < drawList[f].size(); i++){\n            if (drawList[f][i]->treeIndexSize) TerrainPatch::DrawTrees(drawList[f][i], program, PlayerPos, VP);\n        }\n    }\n\n    program->disableVertexAttribArrays();\n    program->unuse();\n\n}\n\nvoid Planet::drawGround(float theta, const Camera* camera, const glm::mat4 &VP, glm::vec3 lightPos, const glm::dvec3 &PlayerPos, const glm::dvec3 &rotPlayerPos, float fadeDistance, bool onPlanet)\n{\n    vg::GLProgram* shader = GameManager::glProgramManager->getProgram(\"GroundFromSpace\");\n    shader->use();\n\n    const i32 textureUnits[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };\n\n    glUniform1iv(glGetUniformLocation(shader->getID(), \"unTextures\"), 6, textureUnits);\n    glUniform1i(glGetUniformLocation(shader->getID(), \"unTexSunGradient\"), textureUnits[6]);\n    glUniform1i(glGetUniformLocation(shader->getID(), \"unTexColor\"), textureUnits[7]);\n\n    f32 m_Kr4PI = atmosphere.m_Kr*4.0f*M_PI;\n    f32 m_Km4PI = atmosphere.m_Km*4.0f*M_PI;\n    f32 m_fScale = 1 / (atmosphere.radius - atmosphere.planetRadius);\n\n    glUniform3f(shader->getUniform(\"unCameraPos\"), (float)rotPlayerPos.x, (float)rotPlayerPos.y, (float)rotPlayerPos.z);\n\n    glUniform3f(shader->getUniform(\"unLightPos\"), lightPos.x, lightPos.y, lightPos.z);\n\n    glUniform3f(shader->getUniform(\"unInvWavelength\"), 1 / atmosphere.m_fWavelength4[0], 1 / atmosphere.m_fWavelength4[1], 1 / atmosphere.m_fWavelength4[2]);\n\n    glUniform1f(shader->getUniform(\"unSpecularExponent\"), graphicsOptions.specularExponent);\n    glUniform1f(shader->getUniform(\"unSpecularIntensity\"), graphicsOptions.specularIntensity);\n    \n    #define MAX_FREEZE_TEMP 255.0f\n\n    glUniform1f(shader->getUniform(\"unCameraHeight2\"), glm::length(PlayerPos)*glm::length(PlayerPos));\n    glUniform1f(shader->getUniform(\"unOuterRadius\"), atmosphere.radius);\n    glUniform1f(shader->getUniform(\"unOuterRadius2\"), atmosphere.radius*atmosphere.radius);\n    glUniform1f(shader->getUniform(\"unInnerRadius\"), atmosphere.planetRadius);\n    glUniform1f(shader->getUniform(\"unKrESun\"), atmosphere.m_Kr*atmosphere.m_ESun);\n    glUniform1f(shader->getUniform(\"unKmESun\"), atmosphere.m_Km*atmosphere.m_ESun);\n    glUniform1f(shader->getUniform(\"unKr4PI\"), m_Kr4PI);\n    glUniform1f(shader->getUniform(\"unKm4PI\"), m_Km4PI);\n    glUniform1f(shader->getUniform(\"unScale\"), m_fScale);\n    glUniform1f(shader->getUniform(\"unScaleDepth\"), atmosphere.m_fRayleighScaleDepth);\n    glUniform1f(shader->getUniform(\"unScaleOverScaleDepth\"), m_fScale / atmosphere.m_fRayleighScaleDepth);\n    glUniform1f(shader->getUniform(\"unNumSamplesF\"), atmosphere.fSamples);\n    glUniform1i(shader->getUniform(\"unNumSamples\"), atmosphere.nSamples);\n    // glUniform1f(shader->getUniform(\"dt\"), bdt); What was this used for?\n    glUniform1f(shader->getUniform(\"unG\"), atmosphere.m_g);\n    glUniform1f(shader->getUniform(\"unG2\"), atmosphere.m_g * atmosphere.m_g);\n    glUniform1f(shader->getUniform(\"unSecColorMult\"), graphicsOptions.secColorMult);\n\n    shader->enableVertexAttribArrays();\n\n    const ui32& mvpID = shader->getUniform(\"unWVP\");\n    const ui32& worldOffsetID = shader->getUniform(\"unWorld\");\n\n    for (size_t i = 0; i < drawList[0].size(); i++){\n        TerrainPatch::Draw(drawList[0][i], camera, PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n    }\n    for (size_t i = 0; i < drawList[2].size(); i++){\n        TerrainPatch::Draw(drawList[2][i], camera, PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n    }\n    for (size_t i = 0; i < drawList[4].size(); i++){\n        TerrainPatch::Draw(drawList[4][i], camera, PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n    }\n    glFrontFace(GL_CW);\n    for (size_t i = 0; i < drawList[5].size(); i++){\n        TerrainPatch::Draw(drawList[5][i], camera, PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n    }\n    for (size_t i = 0; i < drawList[1].size(); i++){\n        TerrainPatch::Draw(drawList[1][i], camera, PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n    }\n    for (size_t i = 0; i < drawList[3].size(); i++){\n        TerrainPatch::Draw(drawList[3][i], camera, PlayerPos, rotPlayerPos, VP, mvpID, worldOffsetID, onPlanet);\n    }\n    glFrontFace(GL_CCW);\n\n    shader->disableVertexAttribArrays();\n\n    shader->unuse();\n}\n\nvoid Planet::updateLODs(glm::dvec3 &worldPosition, GLuint maxTicks)\n{\n    static int k = 0;\n\n    glm::dvec3 rWorldPosition = worldPosition;\n    //glm::dvec3 rWorldPosition = glm::dvec3((glm::dmat4(GameManager::planet->invRotationMatrix)) * glm::dvec4(worldPosition, 1.0));\n\n    int mx = (int)rWorldPosition.x, my = (int)rWorldPosition.y, mz = (int)rWorldPosition.z;\n    for (int n = 0; n < 6; n++){\n        for (unsigned int a = 0; a < faces[n].size(); a++){\n            for (unsigned int b = 0; b < faces[n][a].size(); b++){\n                if (faces[n][a][b]->update(mx, my, mz)){\n                    if (faces[n][a][b]->updateVecIndex == -1){\n                        faces[n][a][b]->updateVecIndex = LODUpdateList.size();\n                        LODUpdateList.push_back(faces[n][a][b]);\n                    }\n                }\n            }\n        }\n    }\n\n    GLuint startTicks = SDL_GetTicks();\n\n    if (LODUpdateList.empty()) return;\n    //cout << LODUpdateList.size() << \" \";\n//    GLuint starttime = SDL_GetTicks();\n    TerrainPatch *lod;\n\n    int wx = (0+CHUNK_WIDTH*csGridWidth/2);\n    int wz = (0+CHUNK_WIDTH*csGridWidth/2);\n    int size = LODUpdateList.size()-1;\n\n    sortUpdateList(); //sorts every update, but insertion sort is fast\n\n    for (int i = size; LODUpdateList.size(); i--)\n    {\n        lod = LODUpdateList.back();\n\n        if (lod->CreateMesh()){\n            LODUpdateList.pop_back();\n            lod->updateVecIndex = -1;\n        }\n        if (SDL_GetTicks() - startTicks > maxTicks){ return; }\n    }\n    \n    k++;\n//    cout << SDL_GetTicks() - starttime << \"     L\\n\";\n}\n\nvoid RecursiveFlagLOD(TerrainPatch *lod){\n    lod->updateCode = 1;\n    if (lod->lods[0]){\n        for(int i = 0; i < 4; i++){\n            RecursiveFlagLOD(lod->lods[i]);\n        }\n    }\n}\n\nvoid Planet::flagTerrainForRebuild()\n{\n    for (int n = 0; n < 6; n++){\n        for (unsigned int a = 0; a < faces[n].size(); a++){\n            for (unsigned int b = 0; b < faces[n][a].size(); b++){\n                RecursiveFlagLOD(faces[n][a][b]);\n                if (faces[n][a][b]->updateVecIndex == -1){\n                    faces[n][a][b]->updateVecIndex = LODUpdateList.size();\n                    LODUpdateList.push_back(faces[n][a][b]);\n                }\n                \n            }\n        }\n    }\n}\n\nvoid Planet::sortUpdateList()\n{\n    TerrainPatch *temp;\n    int j;\n    for (unsigned int i = 1; i < LODUpdateList.size(); i++)\n    {\n        temp = LODUpdateList[i];\n\n        for (j = i - 1; (j >= 0) && (temp->distance > LODUpdateList[j]->distance); j-- ){\n            LODUpdateList[j+1] = LODUpdateList[j];\n            LODUpdateList[j+1]->vecIndex = j+1;\n        }\n\n        LODUpdateList[j+1] = temp;\n        LODUpdateList[j+1]->vecIndex = j+1;\n    }\n}\n\nvoid Planet::destroy()\n{\n    for (size_t i = 0; i < 6; i++){\n        for (size_t j = 0; j < faces[i].size(); j++){\n            for (size_t k = 0; k < faces[i][j].size(); k++){\n                delete faces[i][j][k];\n            }\n        }\n        faces[i].clear();\n    }\n    for (size_t i = 0; i < allBiomesLookupVector.size(); i++){\n        delete allBiomesLookupVector[i];\n    }\n    allBiomesLookupVector.clear();\n\n    for (size_t i = 0; i < floraNoiseFunctions.size(); i++){\n        delete floraNoiseFunctions[i];\n    }\n    floraNoiseFunctions.clear();\n    for (size_t i = 0; i < treeTypeVec.size(); i++){\n        delete treeTypeVec[i];\n    }\n    treeTypeVec.clear();\n    for (size_t i = 0; i < floraTypeVec.size(); i++){\n        delete floraTypeVec[i];\n    }\n    floraTypeVec.clear();\n\n    vg::TextureCache* textureCache = GameManager::textureCache;\n    textureCache->freeTexture(biomeMapTexture);\n    textureCache->freeTexture(sunColorMapTexture);\n    textureCache->freeTexture(sunColorMapTexture);\n    textureCache->freeTexture(waterColorMapTexture);\n}\n\nvoid Planet::clearBiomes() //MEMORY LEAKS ARE ON PURPOSE. NOT MEANT FOR FINAL GAME\n{\n    bindex = 0;\n    allBiomesLookupVector.clear();\n    mainBiomesVector.clear();\n    childBiomesVector.clear();\n    baseBiomesLookupMap.clear();\n}\n\nvoid Planet::addBaseBiome(Biome *baseBiome, int mapColor)\n{\n    baseBiome->vecIndex = bindex++;\n    baseBiomesLookupMap.insert(std::make_pair(mapColor, baseBiome));\n    allBiomesLookupVector.push_back(baseBiome);\n\n    //biome = new Biome; //freed in chunkmanager destructor\n    //biome->name = name;\n    //biome->r = color.r;\n    //biome->g = color.g;\n    //biome->b = color.b;\n    //biome->surfaceBlock = surfaceBlock;\n    //biome->treeChance = treeChance;\n    //biome->vecIndex = index++;\n    //biome->possibleTrees = treetypes;\n    //biome->treeProbabilities = treeprobs;\n    //biome->possibleFlora = floratypes;\n    //biome->floraProbabilities = floraprobs;\n    //biomesLookupMap.insert(make_pair(mapColor, biome));\n    //biomesLookupVector.push_back(biome);\n}\n\nvoid Planet::addMainBiome(Biome *mainBiome)\n{\n    mainBiome->vecIndex = bindex++;\n    allBiomesLookupVector.push_back(mainBiome);\n    mainBiomesVector.push_back(mainBiome);\n}\n\nvoid Planet::addChildBiome(Biome *childBiome)\n{\n    childBiome->vecIndex = bindex++;\n    allBiomesLookupVector.push_back(childBiome);\n    childBiomesVector.push_back(childBiome);\n}\n\ndouble Planet::getGravityAccel(double dist)\n{\n    if (dist < radius) dist = radius;\n    dist = dist*0.5; //convert to meters\n\n    return (mass*M_G/(dist*dist)) * 0.01666 * 0.01666 * 2.0; //divide by 60 twice to account for frames\n}\n\ndouble Planet::getAirFrictionForce(double dist, double velocity)\n{\n    if (dist > atmosphere.radius) return 0.0; //no friction in space duh\n    velocity *= 0.5; //reduce to m/s\n    return 0.25*getAirDensity(dist)*velocity*velocity; //assuming drag of 0.5\n}\n\n\n//earths density is 1.2 kg/m3\n//barometric formula\ndouble Planet::getAirDensity(double dist)\n{\n    double maxDensity = 1.2;\n    double mult;\n    if (dist <= radius) return maxDensity;\n    if (dist >= atmosphere.radius) return 0;\n    mult = (dist-radius)/(atmosphere.radius-radius);\n    return (pow(0.8, mult*20.0)-0.0115) * maxDensity;\n}\n\nAtmosphere::Atmosphere()\n{\n    m_Kr = 0.0025f;        // Rayleigh scattering constant\n    m_Km = 0.0020f;        // Mie scattering constant\n    m_ESun = 25.0f;        // Sun brightness constant\n    m_g = -0.990f;        // The Mie phase asymmetry factor\n    m_fExposure = 2.0f;\n    m_fRayleighScaleDepth = 0.25f; //0.25\n\n    m_fWavelength[0] = 0.650f;        // 650 nm for red\n    m_fWavelength[1] = 0.570f;        // 570 nm for green\n    m_fWavelength[2] = 0.475f;        // 475 nm for blue\n    m_fWavelength4[0] = powf(m_fWavelength[0], 4.0f);\n    m_fWavelength4[1] = powf(m_fWavelength[1], 4.0f);\n    m_fWavelength4[2] = powf(m_fWavelength[2], 4.0f);\n\n    nSamples = 3;\n    fSamples = (float)nSamples;\n}\n\nvoid Atmosphere::initialize(nString filePath, float PlanetRadius)\n{\n    if (filePath.empty()){\n        m_Kr = 0.0025;\n        m_Km = 0.0020;\n        m_ESun = 25.0;\n        m_g = -0.990;\n        m_fExposure = 2.0;\n        m_fWavelength[0] = 0.650;\n        m_fWavelength[1] = 0.570;\n        m_fWavelength[2] = 0.475;\n        nSamples = 3;\n\n        fSamples = (float)nSamples;\n        m_fWavelength4[0] = powf(m_fWavelength[0], 4.0f);\n        m_fWavelength4[1] = powf(m_fWavelength[1], 4.0f);\n        m_fWavelength4[2] = powf(m_fWavelength[2], 4.0f);\n    }\n    else{\n        loadProperties(filePath);\n    }\n\n    radius = PlanetRadius*(1.025);\n    planetRadius = PlanetRadius;\n\n    //std::cout << \"Loading Objects/icosphere.obj... \";\n    //objectLoader.load(\"Objects/icosphere.obj\", vertices, indices);\n    //std::cout << \"Done!\\n\";\n\n    glGenBuffers(1, &(vboID)); // Create the buffer ID\n    glBindBuffer(GL_ARRAY_BUFFER, vboID); // Bind the buffer (vertex array data)\n    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(ColorVertex), NULL, GL_STATIC_DRAW);\n\n    glGenBuffers(1, &(vboIndexID));\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexID);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLushort), NULL, GL_STATIC_DRAW);\n\n    glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(ColorVertex), &(vertices[0].position));\n    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indices.size() * sizeof(GLushort), &(indices[0]));\n    indexSize = indices.size();\n\n    vertices.clear();\n    indices.clear();\n}\n\nvoid Atmosphere::loadProperties(nString filePath)\n{\n    std::vector < std::vector <IniValue> > iniValues;\n    std::vector <nString> iniSections;\n    fileManager.loadIniFile(filePath, iniValues, iniSections);\n\n    int iVal;\n    IniValue *iniVal;\n    for (size_t i = 0; i < iniSections.size(); i++){\n        for (size_t j = 0; j < iniValues[i].size(); j++){\n            iniVal = &(iniValues[i][j]);\n\n            iVal = fileManager.getIniVal(iniVal->key);\n            switch (iVal){\n                case INI_M_KR:\n                    m_Kr = iniVal->getFloat();\n                    break;\n                case INI_M_KM:\n                    m_Km = iniVal->getFloat();\n                    break;\n                case INI_M_ESUN:\n                    m_ESun = iniVal->getFloat();\n                    break;\n                case INI_M_G:\n                    m_g = iniVal->getFloat();\n                    break;\n                case INI_M_EXP:\n                    m_fExposure = iniVal->getFloat();\n                    break;\n                case INI_WAVELENGTHR:\n                    m_fWavelength[0] = iniVal->getFloat();\n                    break;\n                case INI_WAVELENGTHG:\n                    m_fWavelength[1] = iniVal->getFloat();\n                    break;\n                case INI_WAVELENGTHB:\n                    m_fWavelength[2] = iniVal->getFloat();\n                    break;\n                case INI_NSAMPLES:\n                    nSamples = iniVal->getInt();\n                    break;\n            }\n        }\n    }\n\n    fSamples = (float)nSamples;\n    m_fWavelength4[0] = powf(m_fWavelength[0], 4.0f);\n    m_fWavelength4[1] = powf(m_fWavelength[1], 4.0f);\n    m_fWavelength4[2] = powf(m_fWavelength[2], 4.0f);\n}\n\nvoid Atmosphere::draw(float theta, const glm::mat4 &MVP, glm::vec3 lightPos, const glm::dvec3 &ppos) {\n    vg::GLProgram* shader = GameManager::glProgramManager->getProgram(\"Sky\");\n    shader->use();\n\n    glm::mat4 GlobalModelMatrix(1.0);\n    GlobalModelMatrix[0][0] = radius;\n    GlobalModelMatrix[1][1] = radius;\n    GlobalModelMatrix[2][2] = radius;\n    GlobalModelMatrix[3][0] = (f32)-ppos.x;\n    GlobalModelMatrix[3][1] = (f32)-ppos.y;\n    GlobalModelMatrix[3][2] = (f32)-ppos.z;\n\n    // Have to rotate it and draw it again to make a sphere\n    f32v3 EulerAngles(M_PI, 0, 0);\n    f32m4 RotationMatrix = glm::toMat4(glm::quat(EulerAngles));\n    f32m4 MVPr = MVP * GlobalModelMatrix;\n    f32m4 M = GlobalModelMatrix;\n\n    f32 m_Kr4PI = m_Kr * 4.0f* M_PI;\n    f32 m_Km4PI = m_Km * 4.0f* M_PI;\n    f32 m_fScale = 1.0 / (radius - planetRadius);\n\n    glUniformMatrix4fv(shader->getUniform(\"unWVP\"), 1, GL_FALSE, &MVPr[0][0]);\n    glUniform3f(shader->getUniform(\"unCameraPos\"), (float)ppos.x, (float)ppos.y, (float)ppos.z);\n    glUniform3f(shader->getUniform(\"unLightPos\"), lightPos.x, lightPos.y, lightPos.z);\n    glUniform3f(shader->getUniform(\"unInvWavelength\"), 1 / m_fWavelength4[0], 1 / m_fWavelength4[1], 1 / m_fWavelength4[2]);\n    glUniform1f(shader->getUniform(\"unCameraHeight2\"), glm::length(ppos) * glm::length(ppos));\n    glUniform1f(shader->getUniform(\"unOuterRadius\"), radius);\n    glUniform1f(shader->getUniform(\"unOuterRadius2\"), radius * radius);\n    glUniform1f(shader->getUniform(\"unInnerRadius\"), planetRadius);\n    glUniform1f(shader->getUniform(\"unKrESun\"), m_Kr*m_ESun);\n    glUniform1f(shader->getUniform(\"unKmESun\"), m_Km*m_ESun);\n    glUniform1f(shader->getUniform(\"unKr4PI\"), m_Kr4PI);\n    glUniform1f(shader->getUniform(\"unKm4PI\"), m_Km4PI);\n    glUniform1f(shader->getUniform(\"unScale\"), m_fScale);\n    glUniform1f(shader->getUniform(\"unScaleDepth\"), m_fRayleighScaleDepth);\n    glUniform1f(shader->getUniform(\"unScaleOverScaleDepth\"), m_fScale/m_fRayleighScaleDepth);\n    glUniform1f(shader->getUniform(\"unG\"), m_g);\n    glUniform1f(shader->getUniform(\"unG2\"), m_g*m_g);\n    glUniform1i(shader->getUniform(\"unNumSamples\"), nSamples);\n    glUniform1f(shader->getUniform(\"unNumSamplesF\"), fSamples);\n\n    glBindBuffer(GL_ARRAY_BUFFER, vboID);\n\n    shader->enableVertexAttribArrays();\n\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ColorVertex), (void*)0);\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexID);\n\n    glDrawElements(GL_TRIANGLES, indexSize, GL_UNSIGNED_SHORT, 0);\n\n    shader->disableVertexAttribArrays();\n\n    shader->unuse();\n}"
  },
  {
    "path": "SoA/Planet.h",
    "content": "#pragma once\n#include <list>\n#include <set>\n#include <deque>\n#include <queue>\n\n#include <Vorb/types.h>\n#include <Vorb/graphics/Texture.h>\n//#include \"OpenGLStructs.h\"\n//#include \"Texture2d.h\"\n//#include \"WorldStructs.h\"\n#include \"Vertex.h\"\n#include \"Biome.h\"\n\n#define P_TOP 0\n#define P_LEFT 1\n#define P_RIGHT 2\n#define P_FRONT 3\n#define P_BACK 4\n#define P_BOTTOM 5\n\nstruct TreeType;\nstruct PlantType;\nclass Camera;\nclass NoiseInfo;\n\nnamespace vg=vorb::graphics;\n\nstruct AtmosphereProperties {\npublic:\n    f32 rayleighConstant;\n    f32 rayleighScaleDepth;\n    f32 mieConstant;\n    f32 sunIntensity;\n    f32 mieAsymmetry;\n    f32v3 lightWavelengths;\n};\n\nclass Atmosphere {\npublic:\n    Atmosphere();\n\n    void initialize(nString filePath, f32 PlanetRadius);\n    void loadProperties(nString filePath);\n    void draw(f32 theta, const f32m4& MVP, f32v3 lightPos, const f64v3& ppos);\n\n    std::vector<ColorVertex> vertices;\n    std::vector<ui16> indices;\n    ui32 vboID, vbo2ID, vboIndexID, vboIndexID2;\n    ui32 indexSize;\n    f64 radius;\n    f64 planetRadius;\n\n    f32 m_fWavelength[3], m_fWavelength4[3];\n    f32 m_Kr;        // Rayleigh scattering constant\n    f32 m_Km;        // Mie scattering constant\n    f32 m_ESun;        // Sun brightness constant\n    f32 m_g;        // The Mie phase asymmetry factor\n    f32 m_fExposure;\n    f32 m_fRayleighScaleDepth;\n    f32 fSamples;\n    i32 nSamples;\n    i32 debugIndex;\n};\n\nclass Planet {\npublic:\n    Planet();\n    ~Planet();\n\n    void clearMeshes();\n    void initialize(nString filePath);\n    void initializeTerrain(const f64v3& startPosition);\n    void destroy();\n\n    void loadData(nString filePath, bool ignoreBiomes);\n    void saveData();\n\n    void draw(f32 theta, const Camera* camera, f32v3 lightPos, f32 sunVal, f32 fadeDistance, bool connectedToPlanet);\n    void drawTrees(const f32m4& VP, const f64v3& PlayerPos, f32 sunVal);\n    void drawGround(f32 theta, const Camera* camera, const f32m4& VP, f32v3 lightPos, const f64v3& PlayerPos, const f64v3& rotPlayerPos, float fadeDistance, bool onPlanet);\n\n    void updateLODs(f64v3& worldPosition, ui32 maxTicks);\n    void rotationUpdate();\n    void flagTerrainForRebuild();\n    void sortUpdateList();\n\n    void saveProperties(nString filePath);\n    void loadProperties(nString filePath);\n\n    f64 getGravityAccel(f64 dist);\n    f64 getAirFrictionForce(f64 dist, f64 velocity);\n    f64 getAirDensity(f64 dist);\n\n    i32 radius;\n    i32 scaledRadius;\n    i32 solarX, solarY, solarZ;\n    i32 facecsGridWidth;\n    i32 baseTemperature;\n    i32 baseRainfall;\n\n    f32 minHumidity, maxHumidity;\n    f32 minCelsius, maxCelsius;\n\n    f64 axialZTilt;\n    f64 gravityConstant;\n    f64 volume;\n    f64 mass;\n    f64 density;\n    f64 rotationTheta;\n    f64v3 northAxis;\n    f32m4 rotationMatrix;\n    f32m4 invRotationMatrix;\n\n    // GM/r2\n    std::vector< std::vector<class TerrainPatch*> > faces[6];\n    std::vector<TerrainPatch*> LODUpdateList;\n    std::vector<struct TerrainBuffers*> drawList[6];\n\n    //        double axialZTilt[66];\n\n    void clearBiomes();\n    void addBaseBiome(Biome* baseBiome, i32 mapColor);\n    void addMainBiome(Biome* mainBiome);\n    void addChildBiome(Biome* childBiome);\n\n    vg::Texture biomeMapTexture;\n    vg::Texture colorMapTexture;\n    vg::Texture sunColorMapTexture;\n    vg::Texture waterColorMapTexture;\n\n    i32 bindex;\n    std::map<i32, Biome*> baseBiomesLookupMap;\n    std::vector<Biome*> allBiomesLookupVector;\n    std::vector<Biome*> mainBiomesVector;\n    std::vector<Biome*> childBiomesVector;\n\n    std::vector<NoiseInfo*> floraNoiseFunctions;\n    NoiseInfo* stormNoiseFunction;\n    NoiseInfo* sunnyCloudyNoiseFunction;\n    NoiseInfo* cumulusNoiseFunction;\n\n    std::vector<TreeType*> treeTypeVec;\n    std::vector<PlantType*> floraTypeVec;\n\n    i32 maximumDepth;\n    std::vector<ui16> rockLayers;\n\n    std::map<nString, i32> treeLookupMap;\n    std::map<nString, i32> floraLookupMap;\n\n    Atmosphere atmosphere;\n\n    nString dirName;\n    nString biomeMapFileName;\n    nString colorMapFileName;\n    nString waterColorMapFileName;\n\n    f32q axisQuaternion;\n    f32q rotateQuaternion;\n};\n"
  },
  {
    "path": "SoA/PlanetGenData.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PlanetGenData.h\"\n\nKEG_TYPE_DEF_SAME_NAME(BlockLayerKegProperties, kt) {\n    using namespace keg;\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BlockLayerKegProperties, block, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BlockLayerKegProperties, surface, STRING);\n    kt.addValue(\"width\", Value::basic(offsetof(BlockLayerKegProperties, width), BasicType::UI32));\n}\n\nKEG_TYPE_DEF_SAME_NAME(LiquidColorKegProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, LiquidColorKegProperties, colorPath, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, LiquidColorKegProperties, texturePath, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, LiquidColorKegProperties, tint, UI8_V3);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, LiquidColorKegProperties, depthScale, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, LiquidColorKegProperties, freezeTemp, F32);\n}\n\nKEG_TYPE_DEF_SAME_NAME(TerrainColorKegProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainColorKegProperties, colorPath, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainColorKegProperties, grassTexturePath, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainColorKegProperties, rockTexturePath, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, TerrainColorKegProperties, tint, UI8_V3);\n}\n"
  },
  {
    "path": "SoA/PlanetGenData.h",
    "content": "///\n/// PlanetData.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 5 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Structs for planetary data\n///\n\n#pragma once\n\n#ifndef PlanetData_h__\n#define PlanetData_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/graphics/Texture.h>\n#include <Vorb/io/Keg.h>\n\n#include \"Noise.h\"\n#include \"Biome.h\"\n\nDECL_VG(class GLProgram; class BitmapResource);\n\nstruct LiquidColorKegProperties {\n    LiquidColorKegProperties():\n        colorPath(\"\"),\n        texturePath(\"\"),\n        tint(255, 255, 255),\n        depthScale(1000.0f),\n        freezeTemp(-1.0f)\n    {}\n\n    nString colorPath;\n    nString texturePath;\n    ColorRGB8 tint;\n    f32 depthScale;\n    f32 freezeTemp;\n};\nKEG_TYPE_DECL(LiquidColorKegProperties);\n\nstruct TerrainColorKegProperties {\n    TerrainColorKegProperties():\n        colorPath(\"\"),\n        grassTexturePath(\"\"),\n        rockTexturePath(\"\"),\n        tint(255, 255, 255)\n    {}\n\n    nString colorPath;\n    nString grassTexturePath;\n    nString rockTexturePath;\n    ColorRGB8 tint;\n};\nKEG_TYPE_DECL(TerrainColorKegProperties);\n\n// Must match var names for TreeFruitProperties\nstruct FruitKegProperties {\n    FruitKegProperties():\n        flora(\"\"),\n        chance(0.0f)\n    {}\n\n    nString flora = \"\";\n    f32v2 chance = f32v2(0.0f);\n};\n\n// Must match var names for TreeLeafProperties\nstruct LeafKegProperties {\n    LeafKegProperties():\n        type(TreeLeafType::NONE),\n        block(\"none\"),\n        mushGillBlock(\"none\"),\n        mushCapBlock(\"none\")\n    {}\n\n    TreeLeafType type;\n    FruitKegProperties fruitProps;\n    // Union based on type\n    union {\n        struct {\n            i32v2 vRadius;\n            i32v2 hRadius;\n        } round;\n        struct {\n            i32v2 oRadius;\n            i32v2 iRadius;\n            i32v2 period;\n        } pine;\n        struct {\n            i32v2 tvRadius;\n            i32v2 thRadius;\n            i32v2 bvRadius;\n            i32v2 bhRadius;\n            i32v2 bLength;\n            i32v2 capWidth;\n            i32v2 gillWidth;\n            FloraInterpType interp;\n        } mushroom;\n    };\n    // Don't put strings in unions\n    nString block;\n    nString mushGillBlock;\n    nString mushCapBlock;\n};\n\n// Must match var names for TreeBranchProperties\nstruct BranchKegProperties {\n    BranchKegProperties():\n        coreWidth(0),\n        barkWidth(0),\n        widthFalloff(0.1f),\n        branchChance(0.0f),\n        angle(0.0f),\n        subBranchAngle(0.0f),\n        changeDirChance(0.0f),\n        coreBlock(\"\"),\n        barkBlock(\"\")\n    {}\n\n    i32v2 coreWidth;\n    i32v2 barkWidth;\n    f32v2 widthFalloff;\n    f32v2 branchChance;\n    f32v2 angle;\n    f32v2 subBranchAngle;\n    f32v2 changeDirChance;\n    nString coreBlock;\n    nString barkBlock;\n    FruitKegProperties fruitProps;\n    LeafKegProperties leafProps;\n};\n\n// Must match var names for TreeTrunkProperties\nstruct TrunkKegProperties {\n    TrunkKegProperties():\n        loc(0.0f),\n        coreWidth(0),\n        barkWidth(0),\n        branchChance(0.0f),\n        changeDirChance(0.0f),\n        coreBlock(\"\"),\n        barkBlock(\"\"),\n        interp(FloraInterpType::HERMITE)\n    {}\n\n    f32 loc;\n    i32v2 coreWidth;\n    i32v2 barkWidth;\n    f32v2 branchChance;\n    f32v2 changeDirChance;\n    i32v2 slope[2];\n    nString coreBlock;\n    nString barkBlock;\n    FloraInterpType interp;\n    FruitKegProperties fruitProps;\n    LeafKegProperties leafProps;\n    BranchKegProperties branchProps;\n};\n\nstruct BranchVolumeKegProperties {\n    BranchVolumeKegProperties():\n        height(0),\n        hRadius(0),\n        vRadius(0),\n        points(0)\n    {}\n\n    i32v2 height;\n    i32v2 hRadius;\n    i32v2 vRadius;\n    i32v2 points;\n};\n\n// Must match var names for TreeData\nstruct TreeKegProperties {\n    TreeKegProperties():\n        id(\"\"),\n        height(0),\n        branchPoints(0),\n        branchStep(0),\n        killMult(2),\n        infRadius(0.0f)\n    {}\n\n    nString id;\n    i32v2 height;\n    i32v2 branchPoints;\n    i32v2 branchStep;\n    i32v2 killMult;\n    f32v2 infRadius;\n    std::vector<BranchVolumeKegProperties> branchVolumes;\n    std::vector<TrunkKegProperties> trunkProps;\n};\n\nstruct FloraKegProperties {\n    FloraKegProperties():\n        block(\"\"),\n        nextFlora(\"\"),\n        height(1),\n        slope(0),\n        dSlope(0),\n        dir(FloraDir::UP)\n    {}\n\n    nString id;\n    nString block;\n    nString nextFlora;\n    i32v2 height;\n    i32v2 slope;\n    i32v2 dSlope;\n    FloraDir dir;\n};\n\nstruct BlockLayerKegProperties {\n    BlockLayerKegProperties():\n        block(\"\"),\n        surface(\"\"),\n        width(0)\n    {}\n\n    nString block;\n    nString surface;\n    ui32 width;\n};\nKEG_TYPE_DECL(BlockLayerKegProperties);\n\n// Info about what blocks a planet needs\nstruct PlanetBlockInitInfo {\n    PlanetBlockInitInfo():\n        liquidBlockName(\"\"),\n        surfaceBlockName(\"\")\n    {}\n\n    std::map<const Biome*, std::vector<BiomeFloraKegProperties>> biomeFlora;\n    std::map<const Biome*, std::vector<BiomeTreeKegProperties>> biomeTrees;\n    std::vector<TreeKegProperties> trees;\n    std::vector<FloraKegProperties> flora;\n    std::vector<BlockLayerKegProperties> blockLayers;\n    nString liquidBlockName;\n    nString surfaceBlockName;\n};\n\nstruct PlanetGenData {\n    PlanetGenData():\n        terrainColorMap(0),\n        liquidColorMap(0),\n        grassTexture(0),\n        rockTexture(0),\n        liquidTexture(0),\n        liquidTint(255, 255, 255),\n        terrainTint(255, 255, 255),\n        liquidDepthScale(1000.0f),\n        liquidFreezeTemp(-1.0f),\n        tempLatitudeFalloff(0.0f),\n        tempHeightFalloff(0.0f),\n        humLatitudeFalloff(0.0f),\n        humHeightFalloff(0.0f),\n        liquidBlock(0),\n        surfaceBlock(0),\n        radius(0.0)\n    {}\n\n    vg::Texture terrainColorMap;\n    vg::Texture liquidColorMap;\n    vg::Texture grassTexture;\n    vg::Texture rockTexture;\n    vg::Texture liquidTexture;\n    vg::BitmapResource terrainColorPixels;\n    vg::BitmapResource liquidColorPixels;\n    color3 liquidTint;\n    color3 terrainTint;\n    f32 liquidDepthScale;\n    f32 liquidFreezeTemp;\n    f32 tempLatitudeFalloff;\n    f32 tempHeightFalloff;\n    f32 humLatitudeFalloff;\n    f32 humHeightFalloff;\n    PlanetBlockInitInfo blockInfo;\n    std::vector<BlockLayer> blockLayers;\n    ui32 liquidBlock;\n    ui32 surfaceBlock;\n    f64 radius;\n\n    /************************************************************************/\n    /* Base Noise                                                           */\n    /************************************************************************/\n    NoiseBase baseTerrainFuncs;\n    NoiseBase tempTerrainFuncs;\n    NoiseBase humTerrainFuncs;\n\n    /************************************************************************/\n    /* Flora and Trees                                                      */\n    /************************************************************************/\n    std::vector<FloraType> flora;\n    std::map<nString, ui32> floraMap;\n    std::vector<NTreeType> trees;\n    std::map<nString, ui32> treeMap;\n\n    /************************************************************************/\n    /* Biomes                                                               */\n    /************************************************************************/\n    const Biome* baseBiomeLookup[BIOME_MAP_WIDTH][BIOME_MAP_WIDTH];\n    std::vector<BiomeInfluence> baseBiomeInfluenceMap[BIOME_MAP_WIDTH][BIOME_MAP_WIDTH];\n    std::vector<Biome> biomes; ///< Biome object storage. DON'T EVER RESIZE AFTER GEN.\n\n    nString terrainFilePath;\n};\n\n#endif // PlanetData_h__\n"
  },
  {
    "path": "SoA/PlanetGenLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PlanetGenLoader.h\"\n#include \"PlanetGenData.h\"\n\n#include <random>\n\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/Event.hpp>\n#include <Vorb/io/YAML.h>\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/Timing.h>\n\n#include \"BlockPack.h\"\n#include \"Errors.h\"\n#include \"Biome.h\"\n\ntypedef ui32 BiomeColorCode;\n\nPlanetGenData* PlanetGenLoader::m_defaultGenData = nullptr;\n\nstruct BiomeKegProperties {\n    Array<BiomeKegProperties> children;\n    Array<BlockLayer> blockLayers;\n    Array<BiomeFloraKegProperties> flora;\n    Array<BiomeTreeKegProperties> trees;\n    BiomeID id = \"\";\n    ColorRGB8 mapColor = ColorRGB8(255, 255, 255);\n    NoiseBase childNoise; ///< For sub biome determination\n    NoiseBase terrainNoise; ///< Modifies terrain directly\n    f64v2 heightRange = f64v2(0.0, 1000.0);\n    f64v2 heightScale = f64v2(0.01, 0.01);\n    f64v2 noiseRange = f64v2(-1.0, 1.0);\n    f64v2 noiseScale = f64v2(10.0, 10.0);\n    nString displayName = \"Unknown\";\n};\nKEG_TYPE_DECL(BiomeKegProperties);\nKEG_TYPE_DEF_SAME_NAME(BiomeKegProperties, kt) {\n    using namespace keg;\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeKegProperties, id, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeKegProperties, displayName, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeKegProperties, mapColor, UI8_V3);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeKegProperties, heightRange, F64_V2);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeKegProperties, heightScale, F64_V2);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeKegProperties, noiseRange, F64_V2);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, BiomeKegProperties, noiseScale, F64_V2);\n    kt.addValue(\"blockLayers\", Value::array(offsetof(BiomeKegProperties, blockLayers), Value::custom(0, \"BlockLayer\")));\n    kt.addValue(\"terrainNoise\", Value::custom(offsetof(BiomeKegProperties, terrainNoise), \"NoiseBase\", false));\n    kt.addValue(\"flora\", Value::array(offsetof(BiomeKegProperties, flora), Value::custom(0, \"BiomeFloraKegProperties\")));\n    kt.addValue(\"trees\", Value::array(offsetof(BiomeKegProperties, trees), Value::custom(0, \"BiomeTreeKegProperties\")));\n    kt.addValue(\"childNoise\", Value::custom(offsetof(BiomeKegProperties, childNoise), \"NoiseBase\", false));\n    kt.addValue(\"children\", Value::array(offsetof(BiomeKegProperties, children), Value::custom(0, \"BiomeKegProperties\", false)));\n}\n\nvoid PlanetGenLoader::init(vio::IOManager* ioManager) {\n    m_iom = ioManager;\n    m_textureCache.init(ioManager);\n}\n\nCALLER_DELETE PlanetGenData* PlanetGenLoader::loadPlanetGenData(const nString& terrainPath) {\n    nString data;\n    m_iom->readFileToString(terrainPath.c_str(), data);\n\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        std::cout << \"Failed to load \" + terrainPath;\n        context.reader.dispose();\n        return nullptr;\n    }\n\n    PlanetGenData* genData = new PlanetGenData;\n    genData->terrainFilePath = terrainPath;\n\n    nString biomePath = \"\";\n    nString floraPath = \"\";\n    nString treesPath = \"\";\n    // bool didLoadBiomes = false;\n\n    auto f = makeFunctor([&](Sender, const nString& type, keg::Node value) {\n        // Parse based on type\n        if (type == \"biomes\") {\n            biomePath = keg::convert<nString>(value);\n        } else if (type == \"flora\") {\n            floraPath = keg::convert<nString>(value);\n        } else if (type == \"trees\") {\n            treesPath = keg::convert<nString>(value);\n        } else if (type == \"terrainColor\") {\n            parseTerrainColor(context, value, genData);\n        } else if (type == \"liquidColor\") {\n            parseLiquidColor(context, value, genData);\n        } else if (type == \"tempLatitudeFalloff\") {\n            genData->tempLatitudeFalloff = keg::convert<f32>(value);\n        } else if (type == \"humLatitudeFalloff\") {\n            genData->humLatitudeFalloff = keg::convert<f32>(value);\n        } else if (type == \"tempHeightFalloff\") {\n            genData->tempHeightFalloff = keg::convert<f32>(value);\n        } else if (type == \"humHeightFalloff\") {\n            genData->humHeightFalloff = keg::convert<f32>(value);\n        } else if (type == \"baseHeight\") {\n            parseTerrainFuncs(&genData->baseTerrainFuncs, context, value);\n        } else if (type == \"temperature\") {\n            parseTerrainFuncs(&genData->tempTerrainFuncs, context, value);\n        } else if (type == \"humidity\") {\n            parseTerrainFuncs(&genData->humTerrainFuncs, context, value);\n        } else if (type == \"blockLayers\") {\n            parseBlockLayers(context, value, genData);\n        } else if (type == \"liquidBlock\") {\n            genData->blockInfo.liquidBlockName = keg::convert<nString>(value);\n        }\n    });\n    context.reader.forAllInMap(node, &f);\n    context.reader.dispose();\n\n    if (floraPath.size()) {\n        loadFlora(floraPath, genData);\n    }\n    if (treesPath.size()) {\n        loadTrees(treesPath, genData);\n    }\n\n    if (biomePath.size()) {\n        loadBiomes(biomePath, genData);\n    } else {\n        // Set default biome\n        for (int y = 0; y < BIOME_MAP_WIDTH; y++) {\n            for (int x = 0; x < BIOME_MAP_WIDTH; x++) {\n                genData->baseBiomeLookup[y][x] = &DEFAULT_BIOME;\n            }\n        }\n    }\n    return genData;\n}\n\nPlanetGenData* PlanetGenLoader::getDefaultGenData(vcore::RPCManager* glrpc VORB_MAYBE_UNUSED /* = nullptr */) {\n    // Lazily construct default data\n    if (!m_defaultGenData) {\n        // Allocate data\n        m_defaultGenData = new PlanetGenData;\n    }\n    return m_defaultGenData;\n}\n\nCALLER_DELETE PlanetGenData* PlanetGenLoader::getRandomGenData(f32 radius, vcore::RPCManager* glrpc /* = nullptr */) {\n    // Lazily construct default data\n\n    // Allocate data\n    PlanetGenData* genData = m_planetGenerator.generateRandomPlanet(SpaceObjectType::PLANET, glrpc);\n    // TODO(Ben): Radius is temporary hacky fix for small planet darkness!\n    if (radius < 15.0) {\n        genData->baseTerrainFuncs.funcs.setData();\n    }\n\n    // TODO: Reimplement these as suitable.\n    // TODO(Matthew): Note in EVERY case of using RPC, it may be better if RPC owns the function, as otherwise we can't do non-blocking RPC.\n    // Load textures\n    if (glrpc) {\n        vcore::RPC rpc;\n        rpc.data.f = new vcore::RPCFunction(makeFunctor([&](Sender, void*) {\n            genData->grassTexture  = m_textureCache.addTexture(\"_shared/terrain_b.png\", vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n            genData->rockTexture   = m_textureCache.addTexture(\"_shared/terrain_a.png\", vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n            genData->liquidTexture = m_textureCache.addTexture(\"_shared/water_a.png\", vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n        }));\n        glrpc->invoke(&rpc, true);\n        delete rpc.data.f;\n    } else {\n        genData->grassTexture  = m_textureCache.addTexture(\"_shared/terrain_b.png\", vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n        genData->rockTexture   = m_textureCache.addTexture(\"_shared/terrain_a.png\", vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n        genData->liquidTexture = m_textureCache.addTexture(\"_shared/water_a.png\", vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n    }\n\n    // Set default biome\n    for (int y = 0; y < BIOME_MAP_WIDTH; y++) {\n        for (int x = 0; x < BIOME_MAP_WIDTH; x++) {\n            genData->baseBiomeLookup[y][x] = &DEFAULT_BIOME;\n        }\n    }\n\n    return genData;\n}\n\nAtmosphereProperties PlanetGenLoader::getRandomAtmosphere() {\n    static std::mt19937 generator(2636);\n    static std::uniform_real_distribution<f32> randomWav(0.4f, 0.8f);\n    AtmosphereProperties props;\n    props.waveLength.r = randomWav(generator);\n    props.waveLength.g = randomWav(generator);\n    props.waveLength.b = randomWav(generator);\n    return props;\n}\n\n// Helper function for loadBiomes\nui32 recursiveCountBiomes(const BiomeKegProperties& props) {\n    ui32 rv = 1;\n    for (size_t i = 0; i < props.children.size(); i++) {\n        rv += recursiveCountBiomes(props.children[i]);\n    }\n    return rv;\n}\n\nconst int FILTER_SIZE = 5;\nconst int FILTER_OFFSET = FILTER_SIZE / 2;\n\nfloat blurFilter[FILTER_SIZE][FILTER_SIZE] = {\n    {0.04f, 0.04f, 0.04f, 0.04f, 0.04f},\n    {0.04f, 0.04f, 0.04f, 0.04f, 0.04f},\n    {0.04f, 0.04f, 0.04f, 0.04f, 0.04f},\n    {0.04f, 0.04f, 0.04f, 0.04f, 0.04f},\n    {0.04f, 0.04f, 0.04f, 0.04f, 0.04f}\n};\n\nvoid blurBiomeMap(const std::vector<BiomeInfluence>& bMap, OUT std::vector<std::set<BiomeInfluence>>& outMap) {\n    /* Very simple blur function with 5x5 box kernel */\n\n    outMap.resize(bMap.size());\n\n    // Loop through the map\n    for (int y = 0; y < BIOME_MAP_WIDTH; y++) {\n        for (int x = 0; x < BIOME_MAP_WIDTH; x++) {\n            auto& b = bMap[y * BIOME_MAP_WIDTH + x];\n            if (b.b) {\n                // Loop through box filter\n                for (int j = 0; j < FILTER_SIZE; j++) {\n                    for (int k = 0; k < FILTER_SIZE; k++) {\n                        int xPos = (x - FILTER_OFFSET + k);\n                        int yPos = (y - FILTER_OFFSET + j);\n                        // Bounds checking\n                        if (xPos < 0) {\n                            xPos = 0;\n                        } else if (xPos >= BIOME_MAP_WIDTH) {\n                            xPos = BIOME_MAP_WIDTH - 1;\n                        }\n                        if (yPos < 0) {\n                            yPos = 0;\n                        } else if (yPos >= BIOME_MAP_WIDTH) {\n                            yPos = BIOME_MAP_WIDTH - 1;\n                        }\n                        // Get the list of biomes currently in the blurred map\n                        auto& biomes = outMap[yPos * BIOME_MAP_WIDTH + xPos];\n                        // See if the current biome is already there\n                        auto it = biomes.find(b);\n                        // Force modify weight in set with const cast.\n                        // It's ok since weight doesn't affect set position, promise!\n                        if (it == biomes.end()) {\n                            // Add biome and modify weight\n                            const_cast<BiomeInfluence&>(*biomes.insert(b).first).weight = blurFilter[j][k] * b.weight;\n                        } else {\n                            // Modify existing biome weight\n                            const_cast<BiomeInfluence&>(*it).weight += blurFilter[j][k] * b.weight;\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid blurBaseBiomeMap(const Biome* baseBiomeLookup[BIOME_MAP_WIDTH][BIOME_MAP_WIDTH], OUT std::vector<std::set<BiomeInfluence>>& outMap) {\n    /* Very simple blur function with 5x5 box kernel */\n\n    outMap.resize(BIOME_MAP_WIDTH * BIOME_MAP_WIDTH);\n\n    // Loop through the map\n    for (int y = 0; y < BIOME_MAP_WIDTH; y++) {\n        for (int x = 0; x < BIOME_MAP_WIDTH; x++) {\n            auto& b = baseBiomeLookup[y][x];\n            // Loop through box filter\n            for (int j = 0; j < FILTER_SIZE; j++) {\n                for (int k = 0; k < FILTER_SIZE; k++) {\n                    int xPos = (x - FILTER_OFFSET + k);\n                    int yPos = (y - FILTER_OFFSET + j);\n                    // Bounds checking\n                    if (xPos < 0) {\n                        xPos = 0;\n                    } else if (xPos >= BIOME_MAP_WIDTH) {\n                        xPos = BIOME_MAP_WIDTH - 1;\n                    }\n                    if (yPos < 0) {\n                        yPos = 0;\n                    } else if (yPos >= BIOME_MAP_WIDTH) {\n                        yPos = BIOME_MAP_WIDTH - 1;\n                    }\n                    // Get the list of biomes currently in the blurred map\n                    auto& biomes = outMap[yPos * BIOME_MAP_WIDTH + xPos];\n                    // See if the current biome is already there\n                    // TODO(Ben): Better find\n                    auto it = biomes.find({ b, 1.0f });\n                    // Force modify weight in set with const cast.\n                    // It's ok since weight doesn't affect set position, promise!\n                    if (it == biomes.end()) {\n                        // Add biome and set\n                        biomes.emplace(b, blurFilter[j][k]);\n                    } else {\n                        // Modify existing biome weight\n                        const_cast<BiomeInfluence&>(*it).weight += blurFilter[j][k];\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid recursiveInitBiomes(Biome& biome,\n                         const BiomeKegProperties& kp,\n                         ui32& biomeCounter,\n                         PlanetGenData* genData) {\n\n    // Copy all biome data\n    biome.id = kp.id;\n    biome.blockLayers.resize(kp.blockLayers.size());\n    for (size_t i = 0; i < kp.blockLayers.size(); i++) {\n        biome.blockLayers[i] = kp.blockLayers[i];\n    }\n    biome.displayName = kp.displayName;\n    biome.mapColor = kp.mapColor;\n    biome.heightRange = kp.heightRange;\n    biome.heightScale = kp.heightScale;\n    biome.noiseRange = kp.noiseRange;\n    biome.noiseScale = kp.noiseScale;\n    biome.terrainNoise = kp.terrainNoise;\n    biome.childNoise = kp.childNoise;\n\n    // Construct vectors in place for flora and trees\n    auto& floraPropList = genData->blockInfo.biomeFlora.insert(\n        std::make_pair(&biome, std::vector<BiomeFloraKegProperties>())).first->second;\n    auto& treePropList = genData->blockInfo.biomeTrees.insert(\n        std::make_pair(&biome, std::vector<BiomeTreeKegProperties>())).first->second;\n    // Copy flora data over\n    floraPropList.resize(kp.flora.size());\n    for (size_t i = 0; i < kp.flora.size(); i++) {\n        floraPropList[i] = kp.flora[i];\n    }\n    // Copy tree data over\n    treePropList.resize(kp.trees.size());\n    for (size_t i = 0; i < kp.trees.size(); i++) {\n        treePropList[i] = kp.trees[i];\n    }\n\n    // Recurse children\n    biome.children.resize(kp.children.size());\n    for (size_t i = 0; i < kp.children.size(); i++) {\n        Biome& nextBiome = genData->biomes[biomeCounter++];\n        recursiveInitBiomes(nextBiome, kp.children[i], biomeCounter, genData);\n        biome.children[i] = &nextBiome;\n    }\n}\n\n// Conditionally parses a value so it can be either a v2 or a single value\n// When its single, it sets both values of the v2 to that value\n#define PARSE_V2(type, v) \\\nif (keg::getType(value) == keg::NodeType::VALUE) { \\\n    keg::evalData((ui8*)&v, &type##Val, value, context); \\\n    v.y = v.x; \\\n} else { \\\n    keg::evalData((ui8*)&v, &type##v2Val, value, context); \\\n} \n\nvoid PlanetGenLoader::loadFlora(const nString& filePath, PlanetGenData* genData) {\n    // Read in the file\n    nString data;\n    m_iom->readFileToString(filePath.c_str(), data);\n\n    // Get the read context and error check\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        std::cout << \"Failed to load \" + filePath;\n        context.reader.dispose();\n        return;\n    }\n\n    FloraKegProperties* floraProps;\n    // Custom values, must match PARSE_V2 syntax\n    keg::Value i32v2Val = keg::Value::basic(0, keg::BasicType::I32_V2);\n    keg::Value i32Val = keg::Value::basic(0, keg::BasicType::I32);\n    keg::Value stringVal = keg::Value::basic(0, keg::BasicType::STRING);\n    keg::Value floraDirVal = keg::Value::custom(0, \"FloraDir\", true);\n\n    // Parses slope field\n    auto floraParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        if (key == \"block\") {\n            keg::evalData((ui8*)&floraProps->block, &stringVal, value, context);\n        } else if (key == \"child\") {\n            keg::evalData((ui8*)&floraProps->nextFlora, &stringVal, value, context);\n        } else if (key == \"height\") {\n            PARSE_V2(i32, floraProps->height);\n        } else if (key == \"slope\") {\n            PARSE_V2(i32, floraProps->slope);\n        } else if (key == \"dSlope\") {\n            PARSE_V2(i32, floraProps->dSlope);\n        } else if (key == \"dir\") {\n            keg::evalData((ui8*)&floraProps->dir, &floraDirVal, value, context);\n        }\n    });\n\n    auto baseParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        FloraKegProperties properties;\n        properties.id = key;\n        floraProps = &properties;\n        context.reader.forAllInMap(value, &floraParser);\n        genData->blockInfo.flora.push_back(properties);\n    });\n    context.reader.forAllInMap(node, &baseParser);\n    context.reader.dispose();\n}\n\nvoid PlanetGenLoader::loadTrees(const nString& filePath, PlanetGenData* genData) {\n    // Read in the file\n    nString data;\n    m_iom->readFileToString(filePath.c_str(), data);\n\n    // Get the read context and error check\n    // TODO(Ben): Too much copy paste\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        std::cout << \"Failed to load \" + filePath;\n        context.reader.dispose();\n        return;\n    }\n\n    TreeKegProperties* treeProps;\n    // Handles\n    BranchVolumeKegProperties* branchVolProps = nullptr;\n    TrunkKegProperties* trunkProps = nullptr;\n    FruitKegProperties* fruitProps = nullptr;\n    LeafKegProperties* leafProps = nullptr;\n    // Custom values, must match PARSE_V2 syntax\n    keg::Value i32v2Val = keg::Value::basic(0, keg::BasicType::I32_V2);\n    keg::Value i32Val = keg::Value::basic(0, keg::BasicType::I32);\n    keg::Value f32v2Val = keg::Value::basic(0, keg::BasicType::F32_V2);\n    keg::Value f32Val = keg::Value::basic(0, keg::BasicType::F32);\n    keg::Value stringVal = keg::Value::basic(0, keg::BasicType::STRING);\n    keg::Value leafTypeVal = keg::Value::custom(0, \"TreeLeafType\", true);\n    keg::Value interpTypeVal = keg::Value::custom(0, \"FloraInterpType\", true);\n\n    /************************************************************************/\n    /* The following code is ugly because it must be custom parsed with     */\n    /* PARSE_V2. It is *IMPERATIVE* that any added properties be set in     */\n    /* SoaEngine::initVoxelGen as well.                                     */\n    /************************************************************************/\n\n    // Parses fruit field\n    auto fruitParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        if (key == \"id\") {\n            keg::evalData((ui8*)&fruitProps->flora, &stringVal, value, context);\n        } else if (key == \"chance\") {\n            PARSE_V2(f32, fruitProps->chance);\n        }\n    });\n\n    // Parses leaf field\n    auto leafParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        // TODO(Ben): String tokenizer to get rid of string comparisons\n        if (key == \"type\") {\n            keg::evalData((ui8*)&leafProps->type, &leafTypeVal, value, context);\n        } else if (key == \"radius\") {\n            PARSE_V2(i32, leafProps->round.vRadius);\n            leafProps->round.hRadius = leafProps->round.vRadius;\n        } else if (key == \"vRadius\") {\n            PARSE_V2(i32, leafProps->round.vRadius);\n        } else if (key == \"hRadius\") {\n            PARSE_V2(i32, leafProps->round.hRadius);\n        } else if (key == \"oRadius\") {\n            PARSE_V2(i32, leafProps->pine.oRadius);\n        } else if (key == \"iRadius\") {\n            PARSE_V2(i32, leafProps->pine.iRadius);\n        } else if (key == \"period\") {\n            PARSE_V2(i32, leafProps->pine.period);\n        } else if (key == \"block\") {\n            keg::evalData((ui8*)&leafProps->block, &stringVal, value, context);\n        } else if (key == \"fruit\") {\n            fruitProps = &leafProps->fruitProps;\n            context.reader.forAllInMap(value, &fruitParser);\n        } else if (key == \"tvRadius\") {\n            PARSE_V2(i32, leafProps->mushroom.tvRadius);\n        } else if (key == \"thRadius\") {\n            PARSE_V2(i32, leafProps->mushroom.thRadius);\n        } else if (key == \"bvRadius\") {\n            PARSE_V2(i32, leafProps->mushroom.bvRadius);\n        } else if (key == \"bhRadius\") {\n            PARSE_V2(i32, leafProps->mushroom.bhRadius);\n        } else if (key == \"bLength\") {\n            PARSE_V2(i32, leafProps->mushroom.bLength);\n        } else if (key == \"capWidth\") {\n            PARSE_V2(i32, leafProps->mushroom.capWidth);\n        } else if (key == \"gillWidth\") {\n            PARSE_V2(i32, leafProps->mushroom.gillWidth);\n        } else if (key == \"gillBlock\") {\n            keg::evalData((ui8*)&leafProps->mushGillBlock, &stringVal, value, context);\n        } else if (key == \"capBlock\") {\n            keg::evalData((ui8*)&leafProps->mushCapBlock, &stringVal, value, context);\n        } else if (key == \"interp\") {\n            keg::evalData((ui8*)&leafProps->mushroom.interp, &interpTypeVal, value, context);\n        }\n    });\n\n    // Parses branch field\n    auto branchParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        if (key == \"coreWidth\") {\n            PARSE_V2(i32, trunkProps->branchProps.coreWidth);\n        } else if (key == \"barkWidth\") {\n            PARSE_V2(i32, trunkProps->branchProps.barkWidth);\n        } else if (key == \"widthFalloff\") {\n            PARSE_V2(f32, trunkProps->branchProps.widthFalloff);\n        } else if (key == \"angle\") {\n            PARSE_V2(f32, trunkProps->branchProps.angle);\n            // Transform degrees to radians\n            trunkProps->branchProps.angle *= DEG_TO_RAD;\n        } else if (key == \"changeDirChance\") {\n            PARSE_V2(f32, trunkProps->branchProps.changeDirChance);\n        } else if (key == \"subBranchAngle\") {\n            PARSE_V2(f32, trunkProps->branchProps.subBranchAngle);\n            // Transform degrees to radians\n            trunkProps->branchProps.subBranchAngle *= DEG_TO_RAD;\n        } else if (key == \"branchChance\" || key == \"subBranchChance\") {\n            PARSE_V2(f32, trunkProps->branchProps.branchChance);\n        } else if (key == \"block\") {\n            keg::evalData((ui8*)&trunkProps->branchProps.coreBlock, &stringVal, value, context);\n            trunkProps->branchProps.barkBlock = trunkProps->branchProps.coreBlock;\n        } else if (key == \"coreBlock\") {\n            keg::evalData((ui8*)&trunkProps->branchProps.coreBlock, &stringVal, value, context);\n        } else if (key == \"barkBlock\") {\n            keg::evalData((ui8*)&trunkProps->branchProps.barkBlock, &stringVal, value, context);\n        } else if (key == \"fruit\") {\n            fruitProps = &trunkProps->branchProps.fruitProps;\n            context.reader.forAllInMap(value, &fruitParser);\n        } else if (key == \"leaves\") {\n            leafProps = &trunkProps->branchProps.leafProps;\n            context.reader.forAllInMap(value, &leafParser);\n        }\n    });\n\n    // Parses slope field\n    auto slopeParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        if (key == \"min\") {\n            PARSE_V2(i32, trunkProps->slope[0]);\n        } else if (key == \"max\") {\n            PARSE_V2(i32, trunkProps->slope[1]);\n        }\n    });\n\n    // Parses fourth level\n    auto trunkDataParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        if (key == \"loc\") {\n            keg::evalData((ui8*)&trunkProps->loc, &f32Val, value, context);\n        } else if (key == \"coreWidth\") {\n            PARSE_V2(i32, trunkProps->coreWidth);\n        } else if (key == \"barkWidth\") {\n            PARSE_V2(i32, trunkProps->barkWidth);\n        } else if (key == \"branchChance\") {\n            PARSE_V2(f32, trunkProps->branchChance);\n        } else if (key == \"changeDirChance\") {\n            PARSE_V2(f32, trunkProps->changeDirChance);\n        } else if (key == \"slope\") {\n            context.reader.forAllInMap(value, &slopeParser);\n        } else if (key == \"block\") {\n            keg::evalData((ui8*)&trunkProps->coreBlock, &stringVal, value, context);\n            trunkProps->barkBlock = trunkProps->coreBlock;\n        } else if (key == \"coreBlock\") {\n            keg::evalData((ui8*)&trunkProps->coreBlock, &stringVal, value, context);\n        } else if (key == \"barkBlock\") {\n            keg::evalData((ui8*)&trunkProps->barkBlock, &stringVal, value, context);\n        } else if (key == \"fruit\") {\n            fruitProps = &trunkProps->fruitProps;\n            context.reader.forAllInMap(value, &fruitParser);\n        } else if (key == \"branches\") {\n            context.reader.forAllInMap(value, &branchParser);\n        } else if (key == \"leaves\") {\n            leafProps = &trunkProps->leafProps;\n            context.reader.forAllInMap(value, &leafParser);\n        } else if (key == \"interp\") {\n            keg::evalData((ui8*)&trunkProps->interp, &interpTypeVal, value, context);\n        }\n    });\n\n    // Parses third level\n    auto trunkParser = makeFunctor([&](Sender, size_t size VORB_MAYBE_UNUSED, keg::Node value) {\n        treeProps->trunkProps.emplace_back();\n        // Get our handle\n        trunkProps = &treeProps->trunkProps.back();\n        *trunkProps = {}; // Zero it\n        // Default slopes\n        trunkProps->slope[0] = i32v2(1000);\n        trunkProps->slope[1] = i32v2(1000);\n        context.reader.forAllInMap(value, &trunkDataParser);\n        // Avoid div 0\n        if (trunkProps->slope[0].x < 1) trunkProps->slope[0].x = 1;\n        if (trunkProps->slope[0].y < 1) trunkProps->slope[0].y = 1;\n        if (trunkProps->slope[1].x < 1) trunkProps->slope[1].x = 1;\n        if (trunkProps->slope[1].y < 1) trunkProps->slope[1].y = 1;\n    });\n\n    // Parses a branch volume\n    auto branchVolumeParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        if (key == \"height\") {\n            PARSE_V2(i32, branchVolProps->height);\n        } else if (key == \"hRadius\") {\n            PARSE_V2(i32, branchVolProps->hRadius);\n        } else if (key == \"vRadius\") {\n            PARSE_V2(i32, branchVolProps->vRadius);\n        } else if (key == \"radius\") {\n            PARSE_V2(i32, branchVolProps->hRadius);\n            branchVolProps->vRadius = branchVolProps->hRadius;\n        } else if (key == \"points\") {\n            PARSE_V2(i32, branchVolProps->points);\n        }\n    });\n\n    // Parses array of branch volumes\n    auto branchVolumeSeqParser = makeFunctor([&](Sender, size_t size VORB_MAYBE_UNUSED, keg::Node value) {\n        treeProps->branchVolumes.emplace_back();\n        // Get our handle\n        branchVolProps = &treeProps->branchVolumes.back();\n        *branchVolProps = {}; // Zero it\n\n        context.reader.forAllInMap(value, &branchVolumeParser);\n    });\n\n    // Parses second level\n    auto treeParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        if (key == \"height\") {\n            PARSE_V2(i32, treeProps->height);\n        } else if (key == \"branchPoints\") {\n            PARSE_V2(i32, treeProps->branchPoints);\n        } else if (key == \"branchStep\") {\n            PARSE_V2(i32, treeProps->branchStep);\n        } else if (key == \"killMult\") {\n            PARSE_V2(i32, treeProps->killMult);\n        } else if (key == \"infRadius\") {\n            PARSE_V2(f32, treeProps->infRadius);\n        } else if (key == \"branchVolumes\") {\n            context.reader.forAllInSequence(value, &branchVolumeSeqParser);\n        } else if (key == \"trunk\") {\n            context.reader.forAllInSequence(value, &trunkParser);\n        }\n    });\n\n    // Parses top level\n    auto baseParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        genData->blockInfo.trees.emplace_back();\n        treeProps = &genData->blockInfo.trees.back();\n        *treeProps = {}; // Zero it\n        treeProps->id = key;\n        context.reader.forAllInMap(value, &treeParser);\n    });\n    context.reader.forAllInMap(node, &baseParser);\n    context.reader.dispose();\n}\n#undef PARSE_V2\n\nvoid PlanetGenLoader::loadBiomes(const nString& filePath, PlanetGenData* genData) {\n    // Read in the file\n    nString data;\n    m_iom->readFileToString(filePath.c_str(), data);\n\n    // Get the read context and error check\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        std::cout << \"Failed to load \" + filePath;\n        context.reader.dispose();\n        return;\n    }\n\n    // Lookup Maps\n    std::map<BiomeColorCode, Biome*> m_baseBiomeLookupMap; ///< To lookup biomes via color code\n    BiomeColorCode colorCodes[BIOME_MAP_WIDTH][BIOME_MAP_WIDTH];\n\n    std::vector<BiomeKegProperties> baseBiomes;\n\n    // Load yaml data\n    // int i = 0;\n    auto baseParser = makeFunctor([&](Sender, const nString& key, keg::Node value) {\n        // Parse based on type\n        if (key == \"baseLookupMap\") {\n            vpath texPath;\n            m_iom->resolvePath(keg::convert<nString>(value), texPath);\n            vg::ScopedBitmapResource rs(vg::ImageIO().load(texPath.getString(), vg::ImageIOFormat::RGB_UI8, true));\n            if (!rs.data) {\n                pError(\"Failed to load \" + keg::convert<nString>(value));\n            }\n            if (rs.width != BIOME_MAP_WIDTH || rs.height != BIOME_MAP_WIDTH) {\n                pError(\"loadBiomes() error: width and height of \" + keg::convert<nString>(value) +\" must be \" + std::to_string(BIOME_MAP_WIDTH));\n            }\n\n            for (int i = 0; i < BIOME_MAP_WIDTH * BIOME_MAP_WIDTH; i++) {\n                ui8v3& color = rs.bytesUI8v3[i];\n                BiomeColorCode colorCode = ((ui32)color.r << 16) | ((ui32)color.g << 8) | (ui32)color.b;\n                colorCodes[i / BIOME_MAP_WIDTH][i % BIOME_MAP_WIDTH] = colorCode;\n            }\n        } else { // It is a base biome\n            baseBiomes.emplace_back();\n            BiomeKegProperties& props = baseBiomes.back();\n            props.id = key;\n            // Parse it\n            keg::Error error = keg::parse((ui8*)&props, value, context, &KEG_GLOBAL_TYPE(BiomeKegProperties));\n            if (error != keg::Error::NONE) {\n                fprintf(stderr, \"Keg error %d in loadBiomes()\\n\", (int)error);\n                return;\n            }\n        }\n    });\n    context.reader.forAllInMap(node, &baseParser);\n    context.reader.dispose();\n\n    // Get number of biomes\n    ui32 numBiomes = 0;\n    for (auto& kp : baseBiomes) {\n        numBiomes += recursiveCountBiomes(kp);\n    }\n    // Set biome storage\n    genData->biomes.resize(numBiomes);\n    \n    ui32 biomeCounter = 0;\n    for (size_t i = 0; i < baseBiomes.size(); i++) {\n        auto& kp = baseBiomes[i];\n      \n        // Get the biome\n        Biome& biome = genData->biomes[biomeCounter++];\n       \n        // Get the color code and add to map\n        BiomeColorCode colorCode = ((ui32)kp.mapColor.r << 16) | ((ui32)kp.mapColor.g << 8) | (ui32)kp.mapColor.b;\n        m_baseBiomeLookupMap[colorCode] = &biome;\n\n        // Copy all the data over\n        recursiveInitBiomes(biome, kp, biomeCounter, genData);\n    }\n    assert(biomeCounter == genData->biomes.size());\n\n    // Set base biomes\n    memset(genData->baseBiomeLookup, 0, sizeof(genData->baseBiomeLookup));\n    for (int y = 0; y < BIOME_MAP_WIDTH; y++) {\n        for (int x = 0; x < BIOME_MAP_WIDTH; x++) {\n            auto it = m_baseBiomeLookupMap.find(colorCodes[y][x]);\n            if (it != m_baseBiomeLookupMap.end()) {\n                genData->baseBiomeLookup[y][x] = it->second;\n            }\n        }\n    }\n    // Blur base biome map for transition smoothing\n    std::vector<std::set<BiomeInfluence>> outMap;\n    blurBaseBiomeMap(genData->baseBiomeLookup, outMap);\n    // Convert to influence map\n    for (int y = 0; y < BIOME_MAP_WIDTH; y++) {\n        for (int x = 0; x < BIOME_MAP_WIDTH; x++) {\n            genData->baseBiomeInfluenceMap[y][x].resize(outMap[y * BIOME_MAP_WIDTH + x].size());\n            int i = 0;\n            for (auto& b : outMap[y * BIOME_MAP_WIDTH + x]) {\n                genData->baseBiomeInfluenceMap[y][x][i++] = b;\n            }\n        }\n    }\n}\n\nvoid PlanetGenLoader::parseTerrainFuncs(NoiseBase* terrainFuncs, keg::ReadContext& context, keg::Node node) {\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        std::cout << \"Failed to parse node\";\n        return;\n    }\n\n    keg::Error error = keg::parse((ui8*)terrainFuncs, node, context, &KEG_GLOBAL_TYPE(NoiseBase));\n    if (error != keg::Error::NONE) {\n        fprintf(stderr, \"Keg error %d in parseTerrainFuncs()\\n\", (int)error);\n        return;\n    }\n}\n\nvoid PlanetGenLoader::parseLiquidColor(keg::ReadContext& context, keg::Node node, PlanetGenData* genData) {\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        std::cout << \"Failed to parse node\";\n        return;\n    }\n\n    LiquidColorKegProperties kegProps;\n\n    keg::Error error;\n    error = keg::parse((ui8*)&kegProps, node, context, &KEG_GLOBAL_TYPE(LiquidColorKegProperties));\n    if (error != keg::Error::NONE) {\n        fprintf(stderr, \"Keg error %d in parseLiquidColor()\\n\", (int)error);\n        return;\n    }\n\n    // TODO: Reimplement these as suitable.\n    if (kegProps.colorPath.size()) {\n        if (m_glRpc) {\n            vcore::RPC rpc;\n            rpc.data.f = new vcore::RPCFunction(makeFunctor([&](Sender, void*) {\n                //m_textureCache.freeTexture(kegProps.colorPath);\n                //genData->liquidColorMap = m_textureCache.addTexture(kegProps.colorPath,\n                //                                                    genData->liquidColorPixels,\n                //                                                    vg::ImageIOFormat::RGB_UI8,\n                //                                                    vg::TextureTarget::TEXTURE_2D,\n                //                                                    &vg::SamplerState::LINEAR_CLAMP,\n                //                                                    vg::TextureInternalFormat::RGB8,\n                //                                                    vg::TextureFormat::RGB, true);\n            }));\n            m_glRpc->invoke(&rpc, true);\n            delete rpc.data.f;\n        } else {\n            //m_textureCache.freeTexture(kegProps.colorPath);\n            //genData->liquidColorMap = m_textureCache.addTexture(kegProps.colorPath,\n            //                                                    genData->liquidColorPixels,\n            //                                                    vg::ImageIOFormat::RGB_UI8,\n            //                                                    vg::TextureTarget::TEXTURE_2D,\n            //                                                    &vg::SamplerState::LINEAR_CLAMP,\n            //                                                    vg::TextureInternalFormat::RGB8,\n            //                                                    vg::TextureFormat::RGB, true);\n        }\n        // Turn into a color map\n        if (genData->liquidColorMap.id == 0) {\n            vg::ImageIO::free(genData->liquidColorPixels);\n        }\n    }\n    if (kegProps.texturePath.size()) {\n        // TODO: Reimplement these as suitable.\n        // Handle RPC for texture upload\n        if (m_glRpc) {\n            vcore::RPC rpc;\n            rpc.data.f = new vcore::RPCFunction(makeFunctor([&](Sender s VORB_UNUSED, void* userData VORB_UNUSED) {\n                //genData->liquidTexture = m_textureCache.addTexture(kegProps.texturePath, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n            }));\n            m_glRpc->invoke(&rpc, true);\n            delete rpc.data.f;\n        } else {\n            //genData->liquidTexture = m_textureCache.addTexture(kegProps.texturePath, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n        }\n    }\n    genData->liquidFreezeTemp = kegProps.freezeTemp;\n    genData->liquidDepthScale = kegProps.depthScale;\n    genData->liquidTint = kegProps.tint;\n}\n\nvoid PlanetGenLoader::parseTerrainColor(keg::ReadContext& context VORB_MAYBE_UNUSED, keg::Node node, PlanetGenData* genData VORB_MAYBE_UNUSED) {\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        std::cout << \"Failed to parse node\";\n        return;\n    }\n\n    TerrainColorKegProperties kegProps;\n\n    keg::Error error;\n    error = keg::parse((ui8*)&kegProps, node, context, &KEG_GLOBAL_TYPE(TerrainColorKegProperties));\n    if (error != keg::Error::NONE) {\n        fprintf(stderr, \"Keg error %d in parseTerrainColor()\\n\", (int)error);\n        return;\n    }\n\n    if (kegProps.colorPath.size()) {\n        vio::Path p;\n        if (m_iom->resolvePath(kegProps.colorPath, p)) {\n            // Handle RPC for texture upload\n            genData->terrainColorPixels = vg::ImageIO().load(p, vg::ImageIOFormat::RGB_UI8,\n                                                             true);\n        }\n    }\n    // TODO(Ben): stop being lazy and copy pasting\n    if (kegProps.grassTexturePath.size()) {\n        // Handle RPC for texture upload\n        if (m_glRpc) {\n            vcore::RPC rpc;\n            rpc.data.f = new vcore::RPCFunction(makeFunctor([&](Sender s VORB_UNUSED, void* userData VORB_UNUSED) {\n                //genData->grassTexture = m_textureCache.addTexture(kegProps.grassTexturePath, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n            }));\n            m_glRpc->invoke(&rpc, true);\n            delete rpc.data.f;\n        } else {\n            //genData->grassTexture = m_textureCache.addTexture(kegProps.grassTexturePath, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n        }\n    }\n    if (kegProps.rockTexturePath.size()) {\n        // Handle RPC for texture upload\n        if (m_glRpc) {\n            vcore::RPC rpc;\n            rpc.data.f = new vcore::RPCFunction(makeFunctor([&](Sender s VORB_UNUSED, void* userData VORB_UNUSED) {\n                //genData->rockTexture = m_textureCache.addTexture(kegProps.rockTexturePath, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n            }));\n            m_glRpc->invoke(&rpc, true);\n            delete rpc.data.f;\n        } else {\n            //genData->rockTexture = m_textureCache.addTexture(kegProps.rockTexturePath, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n        }\n    }\n    genData->terrainTint = kegProps.tint;\n}\n\nvoid PlanetGenLoader::parseBlockLayers(keg::ReadContext& context, keg::Node node, PlanetGenData* genData) {\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        std::cout << \"Failed to parse node in parseBlockLayers. Should be MAP\";\n        return;\n    }\n\n    auto f = makeFunctor([&](Sender, const nString& name, keg::Node value) {\n        BlockLayerKegProperties layerProps = {};\n        layerProps.block = name;\n        keg::parse((ui8*)&layerProps, value, context, &KEG_GLOBAL_TYPE(BlockLayerKegProperties));\n        genData->blockInfo.blockLayers.push_back(layerProps);\n    });\n    context.reader.forAllInMap(node, &f);\n}\n"
  },
  {
    "path": "SoA/PlanetGenLoader.h",
    "content": "///\n/// PlanetLoader.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 19 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Handles the loading of planet files\n///\n\n#pragma once\n\n#ifndef PlanetLoader_h__\n#define PlanetLoader_h__\n\n#pragma once\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/io/Keg.h>\n#include <Vorb/graphics/TextureCache.h>\n#include <Vorb/VorbPreDecl.inl>\n\n#include \"PlanetGenerator.h\"\n#include \"SpaceSystemLoadStructs.h\"\n\nDECL_VIO(class IOManager);\nDECL_VCORE(class RPCManager);\n\nstruct NoiseBase;\nstruct PlanetGenData;\nstruct BiomeKegProperties;\nclass BlockPack;\n\ntypedef ui32 BiomeColorCode;\n\nclass PlanetGenLoader {\npublic:\n    void init(vio::IOManager* ioManager);\n\n    /// Loads a planet from file\n    CALLER_DELETE PlanetGenData* loadPlanetGenData(const nString& terrainPath);\n    /// Returns a default planetGenData\n    /// @param glrpc: Optional RPC if you want to load on a non-render thread\n    /// @return planet gen data\n    PlanetGenData* getDefaultGenData(vcore::RPCManager* glrpc = nullptr);\n    /// Returns a default planetGenData\n    /// @param glrpc: Optional RPC if you want to load on a non-render thread\n    /// @return planet gen data\n    CALLER_DELETE PlanetGenData* getRandomGenData(f32 radius, vcore::RPCManager* glrpc = nullptr);\n    AtmosphereProperties getRandomAtmosphere();\n\nprivate:\n\n    void loadFlora(const nString& filePath, PlanetGenData* genData);\n    void loadTrees(const nString& filePath, PlanetGenData* genData);\n    void loadBiomes(const nString& filePath, PlanetGenData* genData);\n\n    void parseTerrainFuncs(NoiseBase* terrainFuncs, keg::ReadContext& context, keg::Node node);\n    void parseLiquidColor(keg::ReadContext& context, keg::Node node, PlanetGenData* genData);\n    void parseTerrainColor(keg::ReadContext& context, keg::Node node, PlanetGenData* genData);\n    void parseBlockLayers(keg::ReadContext& context, keg::Node node, PlanetGenData* genData);\n\n    static PlanetGenData* m_defaultGenData; ///< Default generation data handle\n\n    vio::IOManager* m_iom = nullptr; ///< IOManager handle\n\n    vg::TextureCache m_textureCache; ///< Texture cache for re-using textures\n\n    vcore::RPCManager* m_glRpc = nullptr;\n\n    PlanetGenerator m_planetGenerator;\n};\n\n#endif // PlanetLoader_h__\n\n"
  },
  {
    "path": "SoA/PlanetGenerator.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PlanetGenerator.h\"\n\n#include \"ShaderLoader.h\"\n#include \"SoaOptions.h\"\n\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/SamplerState.h>\n\n#define BLUR_PASSES 4\n\nPlanetGenerator::PlanetGenerator() {\n    // Empty\n}\n\nvoid PlanetGenerator::dispose(vcore::RPCManager* glrpc VORB_UNUSED) {\n    // TODO(Ben): Implement\n}\n\nCALLER_DELETE PlanetGenData* PlanetGenerator::generateRandomPlanet(SpaceObjectType type, vcore::RPCManager* glrpc /* = nullptr */) {\n    switch (type) {\n        case SpaceObjectType::PLANET:\n        case SpaceObjectType::DWARF_PLANET:\n        case SpaceObjectType::MOON:\n        case SpaceObjectType::DWARF_MOON:\n            return generatePlanet(glrpc);\n        case SpaceObjectType::ASTEROID:\n            return generateAsteroid(glrpc);\n        case SpaceObjectType::COMET:\n            return generateComet(glrpc);\n        default:\n            return nullptr;\n    }\n}\n\nCALLER_DELETE PlanetGenData* PlanetGenerator::generatePlanet(vcore::RPCManager* glrpc) {\n    PlanetGenData* data = new PlanetGenData;\n    data->terrainColorMap = getRandomColorMap(glrpc, true);\n    data->liquidColorMap = getRandomColorMap(glrpc, true);\n\n    // Falloffs\n    static std::uniform_real_distribution<f32> falloff(0.0f, 100.0f);\n    f32 f = falloff(m_generator);\n    data->tempLatitudeFalloff = f * 1.9f;\n    data->tempHeightFalloff = 5.0f;\n    data->humLatitudeFalloff = f * 0.3f;\n    data->humHeightFalloff = 1.0f;\n\n    std::vector<TerrainFuncProperties> funcs;\n    // Mountains\n    getRandomTerrainFuncs(funcs,\n                          TerrainStage::RIDGED_NOISE,\n                          0, 2,\n                          3, 7,\n                          0.00001f, 0.001f,\n                          -15000.0f, 15000.0f,\n                          100.0f, 30000.0f);\n                          \n    // Terrain\n\n    getRandomTerrainFuncs(funcs,\n                          TerrainStage::NOISE,\n                          2, 5,\n                          1, 4,\n                          0.0002f, 0.2f,\n                          -500.0f, 500.0f,\n                          10.0f, 1000.0f);\n    data->baseTerrainFuncs.funcs.setData(funcs.data(), funcs.size());\n    funcs.clear();\n    // Temperature\n\n    data->tempTerrainFuncs.base = 128.0f;\n    getRandomTerrainFuncs(funcs,\n                          TerrainStage::NOISE,\n                          1, 2,\n                          3, 8,\n                          0.00008f, 0.008f,\n                          -128.0f, -128.0f,\n                          255.0f, 255.0f);\n    data->tempTerrainFuncs.funcs.setData(funcs.data(), funcs.size());\n    funcs.clear();\n    // Humidity\n    data->humTerrainFuncs.base = 128.0f;\n    getRandomTerrainFuncs(funcs,\n                          TerrainStage::NOISE,\n                          1, 2,\n                          3, 8,\n                          0.00008f, 0.008f,\n                          -128.0f, -128.0f,\n                          255.0f, 255.0f);\n    data->humTerrainFuncs.funcs.setData(funcs.data(), funcs.size());\n    funcs.clear();\n\n    return data;\n}\n\nCALLER_DELETE PlanetGenData* PlanetGenerator::generateAsteroid(vcore::RPCManager* glrpc VORB_MAYBE_UNUSED) {\n    PlanetGenData* data = new PlanetGenData;\n    return data;\n}\n\nCALLER_DELETE PlanetGenData* PlanetGenerator::generateComet(vcore::RPCManager* glrpc VORB_MAYBE_UNUSED) {\n    PlanetGenData* data = new PlanetGenData;\n    return data;\n}\n\nVGTexture PlanetGenerator::getRandomColorMap(vcore::RPCManager* glrpc, bool shouldBlur) {\n    static const int WIDTH = 256;\n    color4 pixels[WIDTH][WIDTH];\n    static std::uniform_int_distribution<int> numColors(4, 12);\n    static std::uniform_int_distribution<int> rPos(0, WIDTH - 1);\n    static std::uniform_int_distribution<int> rColor(0, 16777215); // 0-2^24\n\n    int numPoints = numColors(m_generator);\n    std::vector<color4> randColors(numPoints);\n    std::vector<i32v2> randPoints(numPoints);\n    for (int i = 0; i < numPoints; i++) {\n        int newColor = rColor(m_generator);\n        randColors[i].r = (ui8)(newColor >> 16);\n        randColors[i].g = (ui8)((newColor >> 8) & 0xFF);\n        randColors[i].b = (ui8)(newColor & 0xFF);\n        randColors[i].a = (ui8)255;\n        randPoints[i].x = rPos(m_generator);\n        randPoints[i].y = rPos(m_generator);\n    }\n    \n    // Voronoi diagram generation\n    // TODO(Ben): n^3 is slow\n    for (int y = 0; y < WIDTH; y++) {\n        for (int x = 0; x < WIDTH; x++) {\n            int closestDist = INT_MAX;\n            int closestIndex = 0;\n            for (int i = 0; i < numPoints; i++) {\n                int dx = (x - randPoints[i].x);\n                int dy = (y - randPoints[i].y);\n                int dist = dx * dx + dy * dy;\n                if (dist < closestDist) {\n                    closestDist = dist;\n                    closestIndex = i;\n                }\n            }\n            pixels[y][x] = randColors[closestIndex];\n        }\n    }\n\n    // TODO: Implement these as suitable.\n    // Upload texture\n    VGTexture tex = 0;\n    if (glrpc) {\n        vcore::RPC rpc;\n        rpc.data.f = new vcore::RPCFunction(makeFunctor([&](Sender, void*) {\n            tex = vg::GpuMemory::uploadTexture(pixels, WIDTH, WIDTH, vg::TexturePixelType::UNSIGNED_BYTE,\n                                              vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_CLAMP);\n        }));\n        glrpc->invoke(&rpc, true);\n        delete rpc.data.f;\n    } else {\n        tex = vg::GpuMemory::uploadTexture(pixels, WIDTH, WIDTH, vg::TexturePixelType::UNSIGNED_BYTE,\n                                          vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_CLAMP);\n    }\n\n    // Handle Gaussian blur\n    auto f = makeFunctor([&](Sender, void*) {\n        if (!m_blurPrograms[0].isCreated()) {\n            m_blurPrograms[0] = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\",\n                                                                    \"Shaders/PostProcessing/Blur.frag\", nullptr,\n                                                                    \"#define HORIZONTAL_BLUR_9\\n\");\n            m_blurPrograms[1] = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\",\n                                                                    \"Shaders/PostProcessing/Blur.frag\", nullptr,\n                                                                    \"#define VERTICAL_BLUR_9\\n\");\n            m_quad.init();\n            m_targets[0].setSize(WIDTH, WIDTH);\n            m_targets[1].setSize(WIDTH, WIDTH);\n            m_targets[0].init();\n            m_targets[1].init();\n        }\n        // Bind the voronoi color map\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, tex);\n        // Compute BLUR_PASSES passes of 2-pass gaussian blur\n        for (int p = 0; p < BLUR_PASSES; p++) {\n            // Two pass Gaussian blur\n            for (int i = 0; i < 2; i++) {\n                m_blurPrograms[i].use();\n                m_blurPrograms[i].enableVertexAttribArrays();\n\n                glUniform1i(m_blurPrograms[i].getUniform(\"unTex\"), 0);\n                glUniform1f(m_blurPrograms[i].getUniform(\"unSigma\"), 5.0f);\n                glUniform1f(m_blurPrograms[i].getUniform(\"unBlurSize\"), 1.0f / (f32)WIDTH);\n                m_targets[i].use();\n\n                m_quad.draw();\n\n                m_targets[i].unuse((ui32)soaOptions.get(OPT_SCREEN_WIDTH).value.i, (ui32)soaOptions.get(OPT_SCREEN_HEIGHT).value.i);\n                m_blurPrograms[i].disableVertexAttribArrays();\n                m_blurPrograms[i].unuse();\n                m_targets[i].bindTexture();\n            }\n        }\n\n        // Get the pixels and use them to re-upload the texture\n        // TODO(Ben): A direct copy would be more efficient.\n        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);\n        glBindTexture(GL_TEXTURE_2D, tex);\n        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, WIDTH, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);\n    });\n\n    // See if we should use RPC\n    if (shouldBlur) {\n        if (glrpc) {\n            vcore::RPC rpc;\n            rpc.data.f = new vcore::RPCFunction(std::move(f));\n            glrpc->invoke(&rpc, true);\n            delete rpc.data.f;\n        } else {\n            f.invoke(nullptr, nullptr);\n        }\n    }\n    glBindTexture(GL_TEXTURE_2D, 0);\n    return tex;\n}\n\nvoid PlanetGenerator::getRandomTerrainFuncs(OUT std::vector<TerrainFuncProperties>& funcs,\n                                            TerrainStage func,\n                                            int funcsRange1, int funcsRange2,\n                                            int octavesRange1, int octavesRange2,\n                                            float freqRange1, float freqRange2,\n                                            float heightMinRange1, float heightMinRange2,\n                                            float heightWidthRange1, float heightWidthRange2) {\n\n    std::uniform_int_distribution<int> funcsRange(funcsRange1, funcsRange2);\n    std::uniform_int_distribution<int> octavesRange(octavesRange1, octavesRange2);\n    std::uniform_real_distribution<f32> freqRange(freqRange1, freqRange2);\n    std::uniform_real_distribution<f32> heightMinRange(heightMinRange1, heightMinRange2);\n    std::uniform_real_distribution<f32> heightWidthRange(heightWidthRange1, heightWidthRange2);\n\n    int numFuncs = funcsRange(m_generator);\n    if (numFuncs <= 0) return;\n    funcs.resize(funcs.size() + numFuncs);\n\n    for (int i = 0; i < numFuncs; i++) {\n        auto& f = funcs[i];\n        f.func = func;\n        f.low = heightMinRange(m_generator);\n        f.high = f.low + heightWidthRange(m_generator);\n        f.octaves = octavesRange(m_generator);\n        f.frequency = freqRange(m_generator);\n        f.persistence = 0.8f;\n    }\n}"
  },
  {
    "path": "SoA/PlanetGenerator.h",
    "content": "///\n/// PlanetGenerator.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 16 Apr 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Generates random planet data\n///\n\n#pragma once\n\n#ifndef PlanetGenerator_h__\n#define PlanetGenerator_h__\n\n#include \"PlanetGenData.h\"\n#include \"SpaceSystemLoadStructs.h\"\n\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GLRenderTarget.h>\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/graphics/GLProgram.h>\n\n#include <random>\n#include <vector>\n\nstruct PlanetGenData;\n\nclass PlanetGenerator {\npublic:\n    PlanetGenerator();\n    void dispose(vcore::RPCManager* glrpc);\n\n    CALLER_DELETE PlanetGenData* generateRandomPlanet(SpaceObjectType type, vcore::RPCManager* glrpc = nullptr);\nprivate:\n    CALLER_DELETE PlanetGenData* generatePlanet(vcore::RPCManager* glrpc);\n    CALLER_DELETE PlanetGenData* generateAsteroid(vcore::RPCManager* glrpc);\n    CALLER_DELETE PlanetGenData* generateComet(vcore::RPCManager* glrpc);\n    VGTexture getRandomColorMap(vcore::RPCManager* glrpc, bool shouldBlur);\n    void getRandomTerrainFuncs(OUT std::vector<TerrainFuncProperties>& funcs,\n                               TerrainStage func,\n                               int funcsRange1, int funcsRange2,\n                               int octavesRange1, int octavesRange2,\n                               float freqRange1, float freqRange2,\n                               float heightMinRange1, float heightMinRange2,\n                               float heightWidthRange1, float heightWidthRange2);\n\n    vg::FullQuadVBO m_quad;\n    vg::GLRenderTarget m_targets[2];\n    vg::GLProgram m_blurPrograms[2];\n    std::mt19937 m_generator = std::mt19937(36526);\n};\n\n#endif // PlanetGenerator_h__\n"
  },
  {
    "path": "SoA/PlanetHeightData.h",
    "content": "///\n/// PlanetHeightData.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 9 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Heightmap data for planets\n///\n\n#pragma once\n\n#ifndef PlanetHeightData_h__\n#define PlanetHeightData_h__\n\nstruct Biome;\n\nstruct PlanetHeightData {\n    const Biome* biome;\n    f32 height; ///< Height in voxels\n    ui16 flora;\n    ui8 temperature;\n    ui8 humidity;\n    ui8 flags; // TODO(Ben): Bitfield\n};\n\n#endif // PlanetHeightData_h__\n"
  },
  {
    "path": "SoA/PlanetRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PlanetRenderStage.h\"\n\n#include <Vorb/graphics/GLStates.h>\n#include <Vorb/ui/GameWindow.h>\n\n#include \"Chunk.h\"\n#include \"ChunkManager.h\"\n#include \"ChunkIOManager.h\"\n#include \"DebugRenderer.h\"\n#include \"GLProgramManager.h\"\n#include \"GameManager.h\"\n#include \"MeshManager.h\"\n#include \"Options.h\"\n#include \"Player.h\"\n#include \"Planet.h\"\n#include \"SkyboxRenderer.h\"\n#include \"Texture2d.h\"\n#include \"VoxelEditor.h\"\n#include \"VoxelWorld.h\"\n\nPlanetRenderStage::PlanetRenderStage(const Camera* camera) :\n    IRenderStage(camera) {\n    // Empty\n}\n\nvoid PlanetRenderStage::draw() {\n\n    f32m4 VP = _camera->getProjectionMatrix() * _camera->getViewMatrix();\n\n    DepthState::FULL.set();\n    glBlendFunc(GL_ONE, GL_ZERO);\n    GameManager::planet->draw(0, _camera, f32v3(1.0f, 0.0f, 0.0f), 0.1 /*_ambientLight + 0.1*/, _camera->getNearClip() / planetScale, true /*connectedToPlanet*/);\n\n    DepthState::READ.set();\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE);\n    RasterizerState::CULL_CLOCKWISE.set();\n    if (true /*connectedToPlanet*/) {\n        if (!drawMode) GameManager::planet->atmosphere.draw((float)0, VP, glm::vec3((GameManager::planet->invRotationMatrix) * glm::vec4(1.0f, 0.0f, 0.0f, 1.0)), _camera->getPosition());\n    } else {\n        if (!drawMode) GameManager::planet->atmosphere.draw((float)0, VP, f32v3(1.0f, 0.0f, 0.0f), _camera->getPosition());\n    }\n\n\n    DepthState::FULL.set();\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Chunk::vboIndicesID);\n    GameManager::planet->drawTrees(VP, _camera->getPosition(), 0.1f /*ambVal*/);\n}"
  },
  {
    "path": "SoA/PlanetRenderStage.h",
    "content": "/// \n///  PlanetRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the planet rendering stage, which renders\n///  planets and their atmospheres.\n///\n\n#pragma once\n\n#ifndef PlanetRenderStage_h__\n#define PlanetRenderStage_h__\n\n#include <Vorb/graphics/IRenderStage.h>\n\nclass Camera;\n\nclass PlanetRenderStage : public vg::IRenderStage\n{\npublic:\n    /// Constructor which injects dependencies\n    /// @param camera: The camera handle\n    PlanetRenderStage(const Camera* camera);\n\n    /// Draws the render stage\n    virtual void draw() override;\n};\n#endif // PlanetRenderStage_h__\n\n"
  },
  {
    "path": "SoA/PlanetRingsComponentRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"PlanetRingsComponentRenderer.h\"\n\n#include \"SpaceSystem.h\"\n#include \"RenderUtils.h\"\n#include \"soaUtils.h\"\n#include \"ShaderLoader.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/RasterizerState.h>\n#include <Vorb/graphics/ShaderManager.h>\n\nPlanetRingsComponentRenderer::~PlanetRingsComponentRenderer() {\n    dispose();\n}\n\nvoid PlanetRingsComponentRenderer::initGL() {\n    if (!m_program.isCreated()) {\n        m_program = ShaderLoader::createProgramFromFile(\"Shaders/PlanetRings/Rings.vert\",\n                                                        \"Shaders/PlanetRings/Rings.frag\");\n    }\n    if (!m_isInitialized) {\n        m_isInitialized = true;\n        m_quad.init();\n    }\n}\n\nvoid PlanetRingsComponentRenderer::draw(const PlanetRingsComponent& prCmp,\n                                        vecs::EntityID eid,\n                                        const f32m4& VP,\n                                        const f32v3& relCamPos,\n                                        const f32v3& lightPos,\n                                        const f32 planetRadius,\n                                        const f32 zCoef,\n                                        const SpaceLightComponent* spComponent VORB_UNUSED) {\n    // Get renderables\n    // TODO(Ben): Use a renderable component instead\n    std::vector<RenderableRing>* rings;\n    auto it = m_renderableRings.find(eid);\n    if (it == m_renderableRings.end()) {\n        // Look how ugly this line is.\n        rings = &m_renderableRings.insert(std::make_pair(eid, std::vector<RenderableRing>(prCmp.rings.size()))).first->second;\n        for (size_t i = 0; i < prCmp.rings.size(); i++) {\n            auto& rr = rings->operator[](i);\n            rr.ring = prCmp.rings[i];\n            // Load the texture\n            vg::ScopedBitmapResource b(vg::ImageIO().load(rr.ring.texturePath));\n            if (b.data) {\n                rr.texture = vg::GpuMemory::uploadTexture(&b, vg::TexturePixelType::UNSIGNED_BYTE,\n                                                         vg::TextureTarget::TEXTURE_2D,\n                                                         &vg::SamplerState::LINEAR_CLAMP);\n            } else {\n                fprintf(stderr, \"Failed to load %s\\n\", rr.ring.texturePath.getCString());\n            }\n        }\n    } else {\n        rings = &it->second;\n    }\n\n\n    m_program.use();\n    // For logarithmic Z buffer\n    glUniform1f(m_program.getUniform(\"unZCoef\"), zCoef);\n\n    glDisable(GL_CULL_FACE);\n    // Set up matrix\n    for (auto& r : (*rings)) {\n\n        // TODO(Matthew): This statement wasn't used, revisit this function to make sure it is behaving correctly.\n        //f64q invOrientation = glm::inverse(r.ring.orientation);\n\n        // Convert f64q to f32q\n        f32q orientationF32;\n        orientationF32.x = (f32)r.ring.orientation.x;\n        orientationF32.y = (f32)r.ring.orientation.y;\n        orientationF32.z = (f32)r.ring.orientation.z;\n        orientationF32.w = (f32)r.ring.orientation.w;\n        // Convert to matrix\n        f32m4 rotationMatrix = glm::toMat4(orientationF32);\n\n        f32m4 W(1.0);\n        setMatrixScale(W, f32v3(r.ring.outerRadius));\n        setMatrixTranslation(W, -relCamPos);\n        W *= rotationMatrix;\n        f32m4 WVP = VP * W;\n\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, r.texture);\n\n        glUniformMatrix4fv(m_program.getUniform(\"unM\"), 1, GL_FALSE, &W[0][0]);\n        glUniformMatrix4fv(m_program.getUniform(\"unMVP\"), 1, GL_FALSE, &WVP[0][0]);\n        glUniform1f(m_program.getUniform(\"unInnerRadius\"), r.ring.innerRadius);\n        glUniform1f(m_program.getUniform(\"unOuterRadius\"), r.ring.outerRadius);\n        glUniform1i(m_program.getUniform(\"unColorLookup\"), 0);\n        glUniform3fv(m_program.getUniform(\"unLightPos\"), 1, &lightPos[0]);\n        f32v3 planetPos = -relCamPos;\n        glUniform3fv(m_program.getUniform(\"unPlanetPos\"), 1, &planetPos[0]);\n        glUniform1f(m_program.getUniform(\"unPlanetRadius\"), planetRadius);\n\n        m_quad.draw();\n    }\n    glEnable(GL_CULL_FACE);\n    m_program.unuse();\n}\n\nvoid PlanetRingsComponentRenderer::dispose() {\n    if (m_program.isCreated()) m_program.dispose();\n    if (m_isInitialized) {\n        m_quad.dispose();\n        m_isInitialized = false;\n    }\n}\n"
  },
  {
    "path": "SoA/PlanetRingsComponentRenderer.h",
    "content": "///\n/// PlanetRingsComponentRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 23 May 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// The renderer for PlanetRingsComponent\n///\n\n#pragma once\n\n#ifndef PlanetRingsComponentRenderer_h__\n#define PlanetRingsComponentRenderer_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/ecs/ComponentTable.hpp>\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/gtypes.h>\n#include \"SpaceSystemComponents.h\"\n\nstruct SpaceLightComponent;\nstruct PlanetRingsComponent;\n\n// TODO(Ben): Use a renderable component instead\nstruct RenderableRing {\n    PlanetRing ring;\n    VGTexture texture;\n};\n\nclass PlanetRingsComponentRenderer {\npublic:\n    ~PlanetRingsComponentRenderer();\n\n    void initGL();\n    void draw(const PlanetRingsComponent& prCmp,\n              vecs::EntityID eid,\n              const f32m4& VP,\n              const f32v3& relCamPos,\n              const f32v3& lightPos,\n              const f32 planetRadius,\n              const f32 zCoef,\n              const SpaceLightComponent* spComponent);\n    void dispose();\nprivate:\n    // TODO(Ben): Use a renderable component instead\n    std::unordered_map<vecs::EntityID, std::vector<RenderableRing>> m_renderableRings;\n    vg::GLProgram m_program;\n    vg::FullQuadVBO m_quad;\n    bool m_isInitialized = false;\n};\n\n#endif // PlanetRingsComponentRenderer_h__\n"
  },
  {
    "path": "SoA/Positional.h",
    "content": "//\n// Positional.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 28 May 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef Positional_h__\n#define Positional_h__\n\n// TODO(Cristian): Some constants don't belong here\n#include \"Constants.h\"\n\n// TODO(Cristian): Move this to Vorb types.h\n#define soffsetof(T, M) static_cast<size_t>((ptrdiff_t)&(((T*)nullptr)->M))\n\ntypedef i32 VoxelPositionType;\ntypedef glm::tvec3<VoxelPositionType> VoxelVectorType;\n\ninline VoxelPositionType wrapInBounds(VoxelPositionType v) {\n    return v & (CHUNK_WIDTH - 1);\n}\n\nclass VoxelIterablePositionRawX;\nclass VoxelIterablePositionRawY;\nclass VoxelIterablePositionRawZ;\ntemplate<size_t BITS> class VoxelIterablePositionWrapX;\ntemplate<size_t BITS> class VoxelIterablePositionWrapY;\ntemplate<size_t BITS> class VoxelIterablePositionWrapZ;\ntemplate<VoxelPositionType MIN, VoxelPositionType MAX> class VoxelIterablePositionClampX;\ntemplate<VoxelPositionType MIN, VoxelPositionType MAX> class VoxelIterablePositionClampY;\ntemplate<VoxelPositionType MIN, VoxelPositionType MAX> class VoxelIterablePositionClampZ;\n\nstruct VoxelIterablePosition {\npublic:\n    VoxelPositionType x, y, z;\n\n    VoxelIterablePositionRawX& rx() {\n        return reinterpret_cast<VoxelIterablePositionRawX&>(*this);\n    }\n    VoxelIterablePositionRawY& ry() {\n        return reinterpret_cast<VoxelIterablePositionRawY&>(*this);\n    }\n    VoxelIterablePositionRawZ& rz() {\n        return reinterpret_cast<VoxelIterablePositionRawZ&>(*this);\n    }\n\n    template<size_t BITS = 5>\n    VoxelIterablePositionWrapX<BITS>& wx() {\n        return reinterpret_cast<VoxelIterablePositionWrapX<BITS>&>(*this);\n    }\n    template<size_t BITS = 5>\n    VoxelIterablePositionWrapY<BITS>& wy() {\n        return reinterpret_cast<VoxelIterablePositionWrapY<BITS>&>(*this);\n    }\n    template<size_t BITS = 5>\n    VoxelIterablePositionWrapZ<BITS>& wz() {\n        return reinterpret_cast<VoxelIterablePositionWrapZ<BITS>&>(*this);\n    }\n    \n    template<size_t MIN = 0, size_t MAX = CHUNK_WIDTH - 1>\n    VoxelIterablePositionClampX<MIN, MAX>& cx() {\n        return reinterpret_cast<VoxelIterablePositionClampX<MIN, MAX>&>(*this);\n    }\n    template<size_t MIN = 0, size_t MAX = CHUNK_WIDTH - 1>\n    VoxelIterablePositionClampY<MIN, MAX>& cy() {\n        return reinterpret_cast<VoxelIterablePositionClampY<MIN, MAX>&>(*this);\n    }\n    template<size_t MIN = 0, size_t MAX = CHUNK_WIDTH - 1>\n    VoxelIterablePositionClampZ<MIN, MAX>& cz() {\n        return reinterpret_cast<VoxelIterablePositionClampZ<MIN, MAX>&>(*this);\n    }\n\n    operator VoxelVectorType() const {\n        return VoxelVectorType(x, y, z);\n    }\n};\n\n// Check alignment against glm types\n#ifdef _MSC_VER //re-interpret cast cannot be used in constexpr\nstatic_assert(soffsetof(VoxelIterablePosition, x) == soffsetof(VoxelVectorType, x), \"VoxelIterablePosition X is misaligned\");\nstatic_assert(soffsetof(VoxelIterablePosition, y) == soffsetof(VoxelVectorType, y), \"VoxelIterablePosition Y is misaligned\");\nstatic_assert(soffsetof(VoxelIterablePosition, z) == soffsetof(VoxelVectorType, z), \"VoxelIterablePosition Z is misaligned\");\n#endif// _MSC_VER\nstatic_assert(sizeof(VoxelIterablePosition) == sizeof(VoxelVectorType), \"VoxelIterablePosition is of wrong size\");\n\n/*! @brief This operator class modifies value without any modifications.\n * \n * This class only exists to allow for templated code to take advantage of different iterator forms.\n * <br/>\n * pos.x += 5 performs the same modifications as pos.rx() += 5;\n * <br/>\n * although (pos.rx() += 5).ry() += 5 is a valid statement\n */\ntemplate<VoxelPositionType VoxelIterablePosition::*M>\nstruct VoxelIterablePositionRaw : public VoxelIterablePosition {\npublic:\n    VoxelIterablePositionRaw& operator+= (VoxelPositionType v) {\n        this->*M += v;\n        return *this;\n    }\n    VoxelIterablePositionRaw operator+ (VoxelPositionType v) {\n        VoxelIterablePositionRaw pos(*this);\n        pos += v;\n        return pos;\n    }\n//    operator VoxelIterablePosition() const {\n//        return *this;\n//    }\n};\nclass VoxelIterablePositionRawX : public VoxelIterablePositionRaw<&VoxelIterablePosition::x> {};\nclass VoxelIterablePositionRawY : public VoxelIterablePositionRaw<&VoxelIterablePosition::y> {};\nclass VoxelIterablePositionRawZ : public VoxelIterablePositionRaw<&VoxelIterablePosition::z> {};\n\n/*! @brief This operator class wraps values at the end of a modification between [0, (1 << BITS) - 1]\n */\ntemplate<size_t BITS, VoxelPositionType VoxelIterablePosition::*M>\nstruct VoxelIterablePositionWrap : public VoxelIterablePosition {\npublic:\n    static const VoxelPositionType BIT_MASK = (1 << BITS) - 1;\n\n    void wrap() {\n        this->*M &= BIT_MASK;\n    }\n    VoxelIterablePositionWrap& operator+= (VoxelPositionType v) {\n        this->*M += v;\n        this->*M &= BIT_MASK;\n        return *this;\n    }\n    VoxelIterablePositionWrap operator+ (VoxelPositionType v) {\n        VoxelIterablePositionWrap pos(*this);\n        pos += v;\n        return pos;\n    }\n//    operator VoxelIterablePosition() const {\n//        return *this;\n//    }\n};\ntemplate<size_t BITS>\nclass VoxelIterablePositionWrapX : public VoxelIterablePositionWrap<BITS, &VoxelIterablePosition::x> {};\ntemplate<size_t BITS>\nclass VoxelIterablePositionWrapY : public VoxelIterablePositionWrap<BITS, &VoxelIterablePosition::y> {};\ntemplate<size_t BITS>\nclass VoxelIterablePositionWrapZ : public VoxelIterablePositionWrap<BITS, &VoxelIterablePosition::z> {};\n\n/*! @brief This operator class clamps values at the end of a modification between [MIN, MAX]\n */\ntemplate<VoxelPositionType MIN, VoxelPositionType MAX, VoxelPositionType VoxelIterablePosition::*M>\nstruct VoxelIterablePositionClamp : public VoxelIterablePosition {\npublic:\n    void clamp() {\n        if (this->*M > MAX) this->*M = MAX;\n        else if (this->*M < MIN) this->*M = MIN;\n    }\n    VoxelIterablePositionClamp& operator+= (VoxelPositionType v) {\n        this->*M += v;\n        if (this->*M > MAX) this->*M = MAX;\n        else if (this->*M < MIN) this->*M = MIN;\n        return *this;\n    }\n    VoxelIterablePositionClamp operator+ (VoxelPositionType v) {\n        VoxelIterablePositionClamp pos(*this);\n        pos += v;\n        return pos;\n    }\n//    operator VoxelIterablePosition() const {\n//        return *this;\n//    }\n};\ntemplate<VoxelPositionType MIN, VoxelPositionType MAX>\nclass VoxelIterablePositionClampX : public VoxelIterablePositionClamp<MIN, MAX, &VoxelIterablePosition::x> {};\ntemplate<VoxelPositionType MIN, VoxelPositionType MAX>\nclass VoxelIterablePositionClampY : public VoxelIterablePositionClamp<MIN, MAX, &VoxelIterablePosition::y> {};\ntemplate<VoxelPositionType MIN, VoxelPositionType MAX>\nclass VoxelIterablePositionClampZ : public VoxelIterablePositionClamp<MIN, MAX, &VoxelIterablePosition::z> {};\n\nstruct VoxelPosition {\npublic:\n    VoxelIterablePosition chunk;\n    VoxelIterablePosition voxel;\n};\n\n#endif // Positional_h__\n"
  },
  {
    "path": "SoA/ProceduralChunkGenerator.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ProceduralChunkGenerator.h\"\n\n#include \"Chunk.h\"\n#include \"Constants.h\"\n#include \"VoxelSpaceConversions.h\"\n\n#include \"SmartVoxelContainer.hpp\"\n\nvoid ProceduralChunkGenerator::init(PlanetGenData* genData) {\n    m_genData = genData;\n    m_heightGenerator.init(genData);\n}\n\nvoid ProceduralChunkGenerator::generateChunk(Chunk* chunk, PlanetHeightData* heightData) const {\n\n    //int temperature;\n    //int rainfall;\n    int height;\n    int mapHeight;\n    int hIndex;\n    int depth;\n\n    ui16 blockID;\n    ui16 tertiaryData;\n    //double CaveDensity1[9][5][5], CaveDensity2[9][5][5];\n\n    std::vector<BlockLayer>& blockLayers = m_genData->blockLayers;\n    VoxelPosition3D voxPosition = chunk->getVoxelPosition();\n    chunk->numBlocks = 0;\n\n    // Generation data\n    IntervalTree<ui16>::LNode blockDataArray[CHUNK_SIZE];\n    IntervalTree<ui16>::LNode tertiaryDataArray[CHUNK_SIZE];\n    size_t blockDataSize = 0;\n    size_t tertiaryDataSize = 0;\n\n    ui16 c = 0;\n    bool allAir = true;\n\n    ui32 layerIndices[CHUNK_LAYER];\n\n    // First pass at y = 0. We separate it so we can getBlockLayerIndex a single\n    // time and cut out some comparisons.\n    for (size_t z = 0; z < CHUNK_WIDTH; ++z) {\n        for (size_t x = 0; x < CHUNK_WIDTH; ++x, ++c) {\n            tertiaryData = 0;\n\n            mapHeight = (int)heightData[c].height;\n            // TODO(Matthew): These statements weren't used, revisit this function to make sure it is behaving correctly.\n            //temperature = heightData[c].temperature;\n            //rainfall = heightData[c].humidity;\n\n            //tooSteep = (flags & TOOSTEEP) != 0;\n            \n            // TODO(Ben): Fastfloor?\n            height = (int)voxPosition.pos.y;\n            depth = mapHeight - height; // Get depth of voxel\n\n            // Determine the layer\n            if (depth < 0) {\n                layerIndices[c] = 0;\n            } else {\n                allAir = false;\n                layerIndices[c] = getBlockLayerIndex(depth);\n            }\n            BlockLayer& layer = blockLayers[layerIndices[c]];\n            // Get the block ID\n            blockID = getBlockID(chunk, c, depth, mapHeight, height, heightData[c], layer);\n\n            if (blockID != 0) chunk->numBlocks++;\n\n            // Set up the data arrays\n            if (blockDataSize == 0) {\n                blockDataArray[blockDataSize++].set(c, 1, blockID);\n                tertiaryDataArray[tertiaryDataSize++].set(c, 1, tertiaryData);\n            } else {\n                if (blockID == blockDataArray[blockDataSize - 1].data) {\n                    ++blockDataArray[blockDataSize - 1].length;\n                } else {\n                    blockDataArray[blockDataSize++].set(c, 1, blockID);\n                }\n                if (tertiaryData == tertiaryDataArray[tertiaryDataSize - 1].data) {\n                    ++tertiaryDataArray[tertiaryDataSize - 1].length;\n                } else {\n                    tertiaryDataArray[tertiaryDataSize++].set(c, 1, tertiaryData);\n                }\n            }\n        }\n    }\n\n    // Early exit optimization for solid air chunks\n    if (allAir && blockDataSize == 1 && tertiaryDataSize == 1) {\n        // Set up interval trees\n        blockDataArray[0].length = CHUNK_SIZE;\n        tertiaryDataArray[0].length = CHUNK_SIZE;\n        chunk->blocks.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, blockDataArray, blockDataSize);\n        chunk->tertiary.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, tertiaryDataArray, tertiaryDataSize);\n        return;\n    }\n\n    // All the rest of the layers.\n    for (size_t y = 1; y < CHUNK_WIDTH; ++y) {\n        for (size_t z = 0; z < CHUNK_WIDTH; ++z) {\n            for (size_t x = 0; x < CHUNK_WIDTH; ++x, ++c) {\n                tertiaryData = 0;\n                hIndex = (c & 0x3FF); // Same as % CHUNK_LAYER\n\n                mapHeight = heightData[hIndex].height;\n                //temperature = heightData[hIndex].temperature;\n                //rainfall = heightData[hIndex].humidity;\n\n                // TODO(Ben): Fastfloor?\n                height = (int)(y + voxPosition.pos.y);\n                depth = mapHeight - height; // Get depth of voxel\n\n                // Check for going up one layer\n                ui16 layerIndex = layerIndices[hIndex];\n                if (blockLayers[layerIndex].start > (ui32)depth && layerIndex > 0) layerIndex--;\n                // Get the block ID\n                BlockLayer& layer = blockLayers[layerIndex];\n                blockID = getBlockID(chunk, c, depth, mapHeight, height, heightData[hIndex], layer);\n\n                //if (tooSteep) dh += 3; // If steep, increase depth\n\n                // TODO: Modulate dh with noise\n\n                // TODO(Ben): Check for underground\n                \n                if (blockID != 0) ++chunk->numBlocks;\n\n                // Add to the data arrays\n                if (blockID == blockDataArray[blockDataSize - 1].data) {\n                    ++blockDataArray[blockDataSize - 1].length;\n                } else {\n                    blockDataArray[blockDataSize++].set(c, 1, blockID);\n                }\n                if (tertiaryData == tertiaryDataArray[tertiaryDataSize - 1].data) {\n                    ++tertiaryDataArray[tertiaryDataSize - 1].length;\n                } else {\n                    tertiaryDataArray[tertiaryDataSize++].set(c, 1, tertiaryData);\n                }\n            }\n        }\n    }\n    // Set up interval trees\n    chunk->blocks.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, blockDataArray, blockDataSize);\n    chunk->tertiary.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, tertiaryDataArray, tertiaryDataSize);\n}\n\nvoid ProceduralChunkGenerator::generateHeightmap(Chunk* chunk, PlanetHeightData* heightData) const {\n    VoxelPosition3D cornerPos3D = chunk->getVoxelPosition();\n    VoxelPosition2D cornerPos2D;\n    cornerPos2D.pos.x = cornerPos3D.pos.x;\n    cornerPos2D.pos.y = cornerPos3D.pos.z;\n    cornerPos2D.face = cornerPos3D.face;\n\n    for (int z = 0; z < CHUNK_WIDTH; z++) {\n        for (int x = 0; x < CHUNK_WIDTH; x++) {\n            VoxelPosition2D pos = cornerPos2D;\n            pos.pos.x += x;\n            pos.pos.y += z;\n            m_heightGenerator.generateHeightData(heightData[z * CHUNK_WIDTH + x], pos);\n        }\n    }\n}\n\n// Gets layer in O(log(n)) where n is the number of layers\nui32 ProceduralChunkGenerator::getBlockLayerIndex(ui32 depth) const {\n    auto& layers = m_genData->blockLayers;\n\n    // Binary search\n    ui32 lower = 0;\n    ui32 upper=0;\n    \n    if(!layers.empty())\n        upper=layers.size()-1;\n    \n    ui32 pos = (lower + upper) / 2;\n\n    while (lower <= upper) {\n        if (layers[pos].start <= depth && layers[pos].start + layers[pos].width > depth) {\n            // We are in this layer\n            return pos;\n        } else if (layers[pos].start > depth) {\n            upper = pos - 1;\n        } else {\n            lower = pos + 1;\n        }\n        pos = (lower + upper) / 2;\n    }\n    // Just return lowest layer if we fail\n    return layers.size() - 1;\n}\n\n// TODO(Ben): Too many parameters?\nui16 ProceduralChunkGenerator::getBlockID(Chunk* chunk, int blockIndex, int depth, int mapHeight VORB_MAYBE_UNUSED, int height, const PlanetHeightData& hd, BlockLayer& layer) const {\n    ui16 blockID = 0;\n    if (depth > 0) {\n        blockID = layer.block;\n    } else if (depth < 0) {\n        // Liquid\n        if (height < 0 && m_genData->liquidBlock) {\n            blockID = m_genData->liquidBlock;\n        } else if (depth == -1) {\n            if (hd.flora != FLORA_ID_NONE) {\n                // We can determine the flora from the heightData during gen.\n                // Only need to store index.\n                chunk->floraToGenerate.push_back(blockIndex);            \n            }\n        }\n    } else {\n        blockID = layer.surfaceTransform;\n    }\n    return blockID;\n}\n"
  },
  {
    "path": "SoA/ProceduralChunkGenerator.h",
    "content": "///\n/// ProceduralChunkGenerator.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 10 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// \n///\n\n#pragma once\n\n#ifndef ProceduralChunkGenerator_h__\n#define ProceduralChunkGenerator_h__\n\nstruct PlanetGenData;\nstruct PlanetHeightData;\nstruct BlockLayer;\nclass Chunk;\n\n#include \"SphericalHeightmapGenerator.h\"\n\nclass ProceduralChunkGenerator {\npublic:\n    void init(PlanetGenData* genData);\n    void generateChunk(Chunk* chunk, PlanetHeightData* heightData) const;\n    void generateHeightmap(Chunk* chunk, PlanetHeightData* heightData) const;\nprivate:\n    ui32 getBlockLayerIndex(ui32 depth) const;\n    ui16 getBlockID(Chunk* chunk, int blockIndex, int depth, int mapHeight, int height, const PlanetHeightData& hd, BlockLayer& layer) const;\n\n    PlanetGenData* m_genData = nullptr;\n    SphericalHeightmapGenerator m_heightGenerator;\n};\n\n#endif // ProceduralChunkGenerator_h__\n"
  },
  {
    "path": "SoA/ProgramGenDelegate.h",
    "content": "///\n/// ProgramGenDelegate.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 4 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Delegate for generating a shader program\n///\n\n#pragma once\n\n#ifndef ProgramGenDelegate_h__\n#define ProgramGenDelegate_h__\n\n#include \"ShaderLoader.h\"\n\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/graphics/GLProgram.h>\n\nclass ProgramGenDelegate {\npublic:\n    virtual void invoke(Sender sender VORB_MAYBE_UNUSED, void* userData VORB_MAYBE_UNUSED) {\n        printf(\"Building shader: %s\\n\", name);\n        if (isFromFile) {\n            program = ShaderLoader::createProgramFromFile(vs, fs, iom);\n        } else {\n            program = ShaderLoader::createProgram(name, vs, fs);\n        }\n    }\n\n    ProgramGenDelegate() {\n        del = makeDelegate(this, &ProgramGenDelegate::invoke);\n        rpc.data.f = &del;\n    }\n\n    void init(const cString name, const cString vs, const cString fs) {\n        this->name = name;\n        this->vs = vs;\n        this->fs = fs;\n        rpc.data.userData = nullptr;\n        isFromFile = false;\n    }\n\n    void initFromFile(const cString name, const cString vertPath, const cString fragPath, vio::IOManager* iom) {\n        this->name = name;\n        this->vs = vertPath;\n        this->fs = fragPath;\n        this->iom = iom;\n        rpc.data.userData = nullptr;\n        isFromFile = true;\n    }\n\n    const cString name;\n    const cString vs = nullptr;\n    const cString fs = nullptr;\n    bool isFromFile = false;\n\n    vcore::RPC rpc;\n    Delegate<void, Sender, void*> del;\n    vio::IOManager* iom = nullptr;\n\n    vg::GLProgram program;\n    nString errorMessage;\n};\n\n#endif // ProgramGenDelegate_h__\n"
  },
  {
    "path": "SoA/RegionFileManager.cpp",
    "content": "#include \"stdafx.h\"\n#include \"RegionFileManager.h\"\n\n#ifdef VORB_OS_WINDOWS\n#include <direct.h> //for mkdir windows\n#include <io.h>\n#endif//VORB_OS_WINDOWS\n#include <fcntl.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n\n#include <Vorb/utils.h>\n#include <zlib.h>\n\n#include \"Chunk.h\"\n#include \"Errors.h\"\n#include \"GameManager.h\"\n#include \"VoxelSpaceConversions.h\"\n\n// Section tags\n#define TAG_VOXELDATA 0x1\n\n// TODO: Reimplement missing parts and remove VORB_UNUSED tags.\n\n// const char TAG_VOXELDATA_STR[4] = { TAG_VOXELDATA, 0, 0, 0 };\n\ninline i32 fileTruncate(i32 fd, i64 size)\n{\n#if defined(_WIN32) || defined(_WIN64) \n    return _chsize(fd, (long)size);\n#else\n    return ftruncate(fd, size);\n    #define _fileno fileno\n    #define _off_t off_t\n#endif\n}\n\ninline i32 sectorsFromBytes(ui32 bytes) {\n    // Adding 0.1f to be damn sure the cast is right\n    return (i32)(ceil(bytes / (float)SECTOR_SIZE) + 0.1f);\n}\n\n//returns true on error\nbool checkZlibError(nString message, int zerror) {\n    switch (zerror) {\n    case Z_OK:\n        return false;\n    case Z_STREAM_END:\n        pError(\"Zlib \" + message + \" error Z_STREAM_END\");\n        return true;\n    case Z_NEED_DICT:\n        pError(\"Zlib \" + message + \" error Z_NEED_DICT\");\n        return true;\n    case Z_ERRNO:\n        pError(\"Zlib \" + message + \" error Z_ERRNO\");\n        return true;\n    case Z_STREAM_ERROR:\n        pError(\"Zlib \" + message + \" error Z_STREAM_ERROR\");\n        return true;\n    case Z_DATA_ERROR:\n        pError(\"Zlib \" + message + \" error Z_DATA_ERROR\");\n        return true;\n    case Z_MEM_ERROR:\n        pError(\"Zlib \" + message + \" error Z_MEM_ERROR\");\n        return true;\n    case Z_BUF_ERROR:\n        pError(\"Zlib \" + message + \" error Z_BUF_ERROR\");\n        return true;\n    case Z_VERSION_ERROR:\n        pError(\"Zlib \" + message + \" error Z_VERSION_ERROR\");\n        return true;\n    }\n    return false;\n}\n\nRegionFileManager::RegionFileManager(const nString& saveDir) :\n_copySectorsBuffer(nullptr),\n_maxCacheSize(8),\nm_saveDir(saveDir),\n_regionFile(nullptr) {\n    // Empty\n}\n\nRegionFileManager::~RegionFileManager() {\n    clear();\n}\n\nvoid RegionFileManager::clear() {\n    for (size_t i = 0; i < _regionFileCacheQueue.size(); i++) {\n        closeRegionFile(_regionFileCacheQueue[i]);\n    }\n\n    if (_copySectorsBuffer) {\n        delete[] _copySectorsBuffer;\n        _copySectorsBuffer = nullptr;\n    }\n\n    _regionFileCache.clear();\n    _regionFileCacheQueue.clear();\n    _regionFile = nullptr;\n}\n\n// TODO: Investigate why gridPosition isn't used.\nbool RegionFileManager::openRegionFile(nString region, const ChunkPosition3D& gridPosition VORB_UNUSED, bool create) {\n\n    nString filePath;\n    struct stat statbuf;\n    RegionFile* rf;\n\n    if (_regionFile && _regionFile->file && region == _regionFile->region) {\n        return true;\n    }\n\n    flush();\n\n    if (_regionFileCache.size() == _maxCacheSize) {\n        //Remove the oldest region file from the cache\n        rf = _regionFileCacheQueue.front();\n        _regionFileCacheQueue.pop_front();\n        _regionFileCache.erase(rf->region);\n        closeRegionFile(rf);\n    }\n    \n    //Check if it is cached\n    auto rit = _regionFileCache.find(region);\n    if (rit != _regionFileCache.end()) {\n        for (auto it = _regionFileCacheQueue.begin(); it != _regionFileCacheQueue.end(); it++) {\n            if ((*it)->region == region) {\n                RegionFile* rf = (*it);\n                _regionFileCacheQueue.erase(it);\n                _regionFileCacheQueue.push_back(rf);\n                break;\n            }\n        }\n        _regionFile = rit->second;\n        return true;\n    } \n\n\n    filePath = m_saveDir + \"/Region/\" + region + \".soar\";\n   \n    //open file if it exists\n    FILE* file = fopen(filePath.c_str(), \"rb+\");\n\n    //If it doesn't exist\n    if (file == nullptr){\n        //Check if we should create a new region or return false\n        if (create){\n            file = fopen(filePath.c_str(), \"wb+\"); //create the file\n            if (file == nullptr){\n                perror(filePath.c_str());\n                pError(\"Failed to create region file \");\n                return false;\n            }\n        } else{\n            return false;\n        }\n    }\n\n    _regionFile = new RegionFile;\n    memset(_regionFile, 0, sizeof(RegionFile));\n\n    _regionFile->region = region;\n    _regionFile->file = file;\n\n    _regionFileCache[region] = _regionFile;\n    _regionFileCacheQueue.push_back(_regionFile);\n\n    _regionFile->fileDescriptor = _fileno(_regionFile->file); //get file descriptor for truncate if needed\n\n    if (fstat(_regionFile->fileDescriptor, &statbuf) != 0) {\n        pError(\"Stat call failed for region file open\"); //get the file stats\n        return false;\n    }\n    \n    _off_t fileSize = statbuf.st_size;\n\n    //If the file is new, write an empty header\n    if (fileSize == 0){ \n        //Save the empty header\n        if (saveRegionHeader() == false) return false;\n\n        _regionFile->totalSectors = 0;\n        fflush(_regionFile->file);\n    } else{ //load header data into the header class \n\n        if (loadRegionHeader() == false) return false;\n\n        if ((fileSize - sizeof(RegionFileHeader)) % SECTOR_SIZE){\n            pError(filePath + \": Region file chunk storage must be multiple of \" + std::to_string(SECTOR_SIZE) + \". Remainder = \" + std::to_string(sectorsFromBytes(fileSize - sizeof(RegionFileHeader))));\n            return false;\n        }\n\n        _regionFile->totalSectors = sectorsFromBytes(fileSize - sizeof(RegionFileHeader));\n    }\n\n    return true;\n}\n\nvoid RegionFileManager::closeRegionFile(RegionFile* regionFile) {\n\n    if (regionFile->file == nullptr) return;\n\n    if (_regionFile->isHeaderDirty) {\n        saveRegionHeader();\n    }\n\n    fclose(regionFile->file);\n    delete regionFile;\n}\n\n//Attempt to load a chunk. Returns false on failure\nbool RegionFileManager::tryLoadChunk(Chunk* chunk VORB_UNUSED) {\n\n    //nString regionString = getRegionString(chunk);\n\n    ////Open the region file\n    //if (!openRegionFile(regionString, chunk->gridPosition, false)) return false;\n\n    ////Get the chunk sector offset\n    //ui32 chunkSectorOffset = getChunkSectorOffset(chunk);\n    ////If chunkOffset is zero, it hasnt been saved\n    //if (chunkSectorOffset == 0) {\n    //    return false;\n    //}\n\n    ////Location is not stored zero indexed, so that 0 indicates that it hasnt been saved\n    //chunkSectorOffset -= 1;\n\n    ////Seek to the chunk header\n    //if (!seekToChunk(chunkSectorOffset)){\n    //    pError(\"Region: Chunk data fseek C error! \" + std::to_string(sizeof(RegionFileHeader)+chunkSectorOffset * SECTOR_SIZE) + \" size: \" + std::to_string(_regionFile->totalSectors));\n    //    return false;\n    //}\n\n    ////Get the chunk header\n    //if (!readChunkHeader()) return false;\n\n    //// Read all chunk data\n    //if (!readChunkData_v0()) return false;\n    //\n    //// Read all tags and process the data\n    //_chunkOffset = 0;\n    //while (_chunkOffset < _chunkBufferSize) {\n    //    // Read the tag\n    //    ui32 tag = BufferUtils::extractInt(_chunkBuffer, _chunkOffset);\n    //    _chunkOffset += sizeof(ui32);\n\n    //    switch (tag) {\n    //        case TAG_VOXELDATA:\n    //            //Fill the chunk with the aquired data\n    //            if (!fillChunkVoxelData(chunk)) return false;\n    //            break;\n    //        default:\n    //            std::cout << \"INVALID TAG \" << tag << std::endl;\n    //            return false;\n    //    }\n    //}\n    //return true;\n    return true;\n}\n\n//Saves a chunk to a region file\nbool RegionFileManager::saveChunk(Chunk* chunk VORB_UNUSED) {\n\n    ////Used for copying sectors if we need to resize the file\n    //if (_copySectorsBuffer) {\n    //    delete[] _copySectorsBuffer;\n    //    _copySectorsBuffer = nullptr;\n    //}\n\n    //nString regionString = getRegionString(chunk);\n\n    //if (!openRegionFile(regionString, chunk->gridPosition, true)) return false;\n\n    //ui32 tableOffset;\n    //ui32 chunkSectorOffset = getChunkSectorOffset(chunk, &tableOffset);\n\n    //i32 numOldSectors;\n\n    ////If chunkOffset is zero, then we need to add the entry\n    //if (chunkSectorOffset == 0) {\n\n    //    //Set the sector offset in the table\n    //    BufferUtils::setInt(_regionFile->header.lookupTable, tableOffset, _regionFile->totalSectors + 1); //we add 1 so that 0 can indicate not saved\n    //    _regionFile->isHeaderDirty = true;\n\n    //    chunkSectorOffset = _regionFile->totalSectors;\n\n    //    numOldSectors = 0;\n    //  \n    //} else {\n    //    //Convert sector offset from 1 indexed to 0 indexed\n    //    chunkSectorOffset--;\n    //    //seek to the chunk\n    //    if (!seekToChunk(chunkSectorOffset)){\n    //        pError(\"Region: Chunk data fseek save error BB! \" + std::to_string(chunkSectorOffset));\n    //        return false;\n    //    }\n\n    //    //Get the chunk header\n    //    if (!readChunkHeader()) return false;\n    //    ui32 oldDataLength = BufferUtils::extractInt(_chunkHeader.dataLength);\n    //    numOldSectors = sectorsFromBytes(oldDataLength + sizeof(ChunkHeader));\n\n    //    if (numOldSectors > _regionFile->totalSectors) {\n    //        std::cout << (std::to_string(chunkSectorOffset) + \" \" + std::to_string(tableOffset) + \"Chunk Header Corrupted\\n\");\n    //        return false;\n    //    }\n    //}\n\n    ////Compress the chunk data\n    //rleCompressChunk(chunk);\n    //zlibCompress();\n\n    //i32 numSectors = sectorsFromBytes(_compressedBufferSize);\n    //i32 sectorDiff = numSectors - numOldSectors;\n\n    ////If we need to resize the number of sectors in the file and this chunk is not at the end of file,\n    ////then we should copy all sectors at the end of the file so we can resize it. This operation should be\n    ////fairly rare.\n    //if ((sectorDiff != 0) && ((chunkSectorOffset + numOldSectors) != _regionFile->totalSectors)) {\n    //    if (!seekToChunk(chunkSectorOffset + numOldSectors)){\n    //        pError(\"Region: Failed to seek for sectorCopy \" + std::to_string(chunkSectorOffset) + \" \" + std::to_string(numOldSectors) + \" \" + std::to_string(_regionFile->totalSectors));\n    //        return false;\n    //    }\n\n    //    _copySectorsBufferSize = (_regionFile->totalSectors - (chunkSectorOffset + numOldSectors)) * SECTOR_SIZE;\n    //    _copySectorsBuffer = new ui8[_copySectorsBufferSize]; //for storing all the data that will need to be copied in the end\n    //   \n    //    readSectors(_copySectorsBuffer, _copySectorsBufferSize);\n    //}\n\n    ////Set the header data\n    //BufferUtils::setInt(_chunkHeader.compression, COMPRESSION_RLE | COMPRESSION_ZLIB);\n    //BufferUtils::setInt(_chunkHeader.timeStamp, 0);\n    //BufferUtils::setInt(_chunkHeader.dataLength, _compressedBufferSize - sizeof(ChunkHeader));\n\n    ////Copy the header data to the write buffer\n    //memcpy(_compressedByteBuffer, &_chunkHeader, sizeof(ChunkHeader));\n\n    ////seek to the chunk\n    //if (!seekToChunk(chunkSectorOffset)){\n    //    pError(\"Region: Chunk data fseek save error GG! \" + std::to_string(chunkSectorOffset));\n    //    return false;\n    //}\n\n    ////Write the header and data\n    //writeSectors(_compressedByteBuffer, (ui32)_compressedBufferSize);\n\n    ////Keep track of total sectors in file so we can infer filesize\n    //_regionFile->totalSectors += sectorDiff;\n\n    ////If we need to move some sectors around\n    //if (_copySectorsBuffer) {\n   \n    //    if (!seekToChunk(chunkSectorOffset + numSectors)){\n    //        pError(\"Region: Chunk data fseek save error GG! \" + std::to_string(chunkSectorOffset));\n    //        return false;\n    //    }\n    //    //Write the buffer of sectors\n    //    writeSectors(_copySectorsBuffer, _copySectorsBufferSize);\n    //    delete[] _copySectorsBuffer;\n    //    _copySectorsBuffer = nullptr;\n\n    //    //if the file got smaller\n    //    if (sectorDiff < 0){\n    //        //truncate the file\n    //        if (fileTruncate(_regionFile->fileDescriptor, sizeof(RegionFileHeader)+_regionFile->totalSectors * SECTOR_SIZE) != 0) {\n    //            perror(\"Region file: Truncate error!\\n\");\n    //        }\n    //    }\n\n    //    //Update the table\n    //    ui32 nextChunkSectorOffset;\n    //    for (int i = 0; i < REGION_SIZE * 4; i += 4){\n    //        nextChunkSectorOffset = BufferUtils::extractInt(_regionFile->header.lookupTable, i);\n    //        //See if the 1 indexed nextChunkSectorOffset is > the 0 indexed chunkSectorOffset\n    //        if (nextChunkSectorOffset > (chunkSectorOffset + 1)){ \n    //            BufferUtils::setInt(_regionFile->header.lookupTable, i, nextChunkSectorOffset + sectorDiff);\n    //        } \n    //    }\n    //    _regionFile->isHeaderDirty = true;\n    //}\n    //fflush(_regionFile->file);\n    return true;\n}\n\nvoid RegionFileManager::flush() {\n    if (_regionFile && _regionFile->file) {\n        if (_regionFile->isHeaderDirty) {\n            saveRegionHeader();\n            fflush(_regionFile->file);\n        }  \n    }\n}\n\nbool RegionFileManager::saveVersionFile() {\n    FILE* file;\n    file = fopen((m_saveDir + \"/Region/version.dat\").c_str(), \"wb\");\n\n    if (!file) return false;\n\n    SaveVersion currentVersion;\n    BufferUtils::setInt(currentVersion.regionVersion, CURRENT_REGION_VER);\n\n    fwrite(&currentVersion, 1, sizeof(SaveVersion), file);\n    fclose(file);\n    return true;\n}\n\nbool RegionFileManager::checkVersion() {\n    FILE* file;\n    file = fopen((m_saveDir + \"/Region/version.dat\").c_str(), \"rb\");\n\n    if (!file) {\n        pError(m_saveDir + \"/Region/version.dat not found. Game will assume the version is correct, but it is \"\n               + \"probable that this save will not work if the version is wrong. If this is a save from 0.1.6 or earlier, then it is \"\n               + \"only compatible with version 0.1.6 of the game. In that case, please make a new save or download 0.1.6 to play this save.\");\n        return saveVersionFile();\n    }\n    SaveVersion version;\n\n    fread(&version, 1, sizeof(SaveVersion), file);\n\n    ui32 regionVersion = BufferUtils::extractInt(version.regionVersion);\n   \n    if (regionVersion != CURRENT_REGION_VER) {\n        return tryConvertSave(regionVersion);\n    }\n    return true;\n}\n\nbool RegionFileManager::readChunkHeader() {\n    if (fread(&(_chunkHeader), 1, sizeof(ChunkHeader), _regionFile->file) != sizeof(ChunkHeader)) {\n        return false;\n    }\n    return true;\n}\n\nbool RegionFileManager::readChunkData_v0() {\n\n    ui32 dataLength = BufferUtils::extractInt(_chunkHeader.dataLength);\n\n    if (dataLength > sizeof(_compressedByteBuffer)) {\n        pError(\"Region voxel input buffer overflow\");\n        return false;\n    }\n\n    if (fread(_compressedByteBuffer, 1, dataLength, _regionFile->file) != dataLength) {\n        std::cout << \"Did not read enough bytes at Z\\n\";\n        return false;\n    }\n\n    _chunkBufferSize = CHUNK_DATA_SIZE + CHUNK_SIZE * 2;\n    int zresult = uncompress(_chunkBuffer, &_chunkBufferSize, _compressedByteBuffer, dataLength);\n\n    return (!checkZlibError(\"decompression\", zresult));\n \n}\n\nint RegionFileManager::rleUncompressArray(ui8* data, ui32& byteIndex, int jStart, int jMult, int jEnd, int jInc, int kStart, int kMult, int kEnd, int kInc) {\n\n    ui8 value;\n    ui16 runSize;\n    int index;\n\n    int i = 0; //y\n    int j = jStart; //z\n    int k = kStart; //x\n    int blockCounter = 0;\n\n    //Read block data\n    while (blockCounter < CHUNK_SIZE){\n        //Grab a run of RLE data\n        runSize = BufferUtils::extractShort(_chunkBuffer, byteIndex);\n        value = _chunkBuffer[byteIndex + 2];\n\n        for (int q = 0; q < runSize; q++){\n            index = i * CHUNK_LAYER + j * jMult + k * kMult;\n\n            if (index >= CHUNK_SIZE){\n                pError(\"Chunk File Corrupted! Index >= 32768. (\" + std::to_string(index) + \") \" + std::to_string(q) + \" \" + std::to_string(runSize) + \" \" + std::to_string(blockCounter));\n                return 1;\n            }\n\n            data[index] = value;\n\n            blockCounter++;\n            k += kInc;\n            if (k == kEnd){\n                k = kStart;\n                j += jInc;\n                if (j == jEnd){\n                    j = jStart;\n                    i++;\n                }\n            }\n        }\n        byteIndex += 3;\n    }\n    return 0;\n}\n\nint RegionFileManager::rleUncompressArray(ui16* data, ui32& byteIndex, int jStart, int jMult, int jEnd, int jInc, int kStart, int kMult, int kEnd, int kInc) {\n    \n    ui16 value;\n    ui16 runSize;\n    int index;\n\n    int i = 0; //y\n    int j = jStart; //z\n    int k = kStart; //x\n    int blockCounter = 0;\n\n    //Read block data\n    while (blockCounter < CHUNK_SIZE){\n        //Grab a run of RLE data\n        runSize = BufferUtils::extractShort(_chunkBuffer, byteIndex);\n        value = BufferUtils::extractShort(_chunkBuffer, byteIndex + 2);\n\n        for (int q = 0; q < runSize; q++){\n            index = i * CHUNK_LAYER + j * jMult + k * kMult;\n\n            if (index >= CHUNK_SIZE){\n                pError(\"Chunk File Corrupted! Index >= 32768. (\" + std::to_string(index) + \") \" + std::to_string(q) + \" \" + std::to_string(runSize) + \" \" + std::to_string(blockCounter));\n                return 1;\n            }\n\n            data[index] = value;\n\n            blockCounter++;\n            k += kInc;\n            if (k == kEnd){\n                k = kStart;\n                j += jInc;\n                if (j == jEnd){\n                    j = jStart;\n                    i++;\n                }\n            }\n        }\n        byteIndex += 4;\n    }\n    return 0;\n}\n\nbool RegionFileManager::fillChunkVoxelData(Chunk* chunk VORB_UNUSED) {\n\n    // TODO(Ben): Fix\n\n    //ui8 lightVal;\n\n    //int blockIndex;\n    //int jStart, jEnd, jInc;\n    //int kStart, kEnd, kInc;\n    //int jMult, kMult;\n\n    //chunk->voxelMapData->getIterationConstants(jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc);\n\n    //chunk->numBlocks = 0;\n\n    //if (rleUncompressArray(_blockIDBuffer, _chunkOffset, jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc)) return false;\n\n    //if (rleUncompressArray(_lampLightBuffer, _chunkOffset, jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc)) return false;\n\n    //if (rleUncompressArray(_sunlightBuffer, _chunkOffset, jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc)) return false;\n\n    //if (rleUncompressArray(_tertiaryDataBuffer, _chunkOffset, jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc)) return false;\n\n\n    ////Node buffers, reserving maximum memory so we don't ever need to reallocate. Static so that the memory persists.\n    //static std::vector<IntervalTree<ui16>::LNode> blockIDNodes(CHUNK_SIZE, IntervalTree<ui16>::LNode(0, 0, 0));\n    //static std::vector<IntervalTree<ui16>::LNode> lampLightNodes(CHUNK_SIZE, IntervalTree<ui16>::LNode(0, 0, 0));\n    //static std::vector<IntervalTree<ui8>::LNode> sunlightNodes(CHUNK_SIZE, IntervalTree<ui8>::LNode(0, 0, 0));\n    //static std::vector<IntervalTree<ui16>::LNode> tertiaryDataNodes(CHUNK_SIZE, IntervalTree<ui16>::LNode(0, 0, 0));\n\n    ////Make the size 0\n    //blockIDNodes.clear();\n    //lampLightNodes.clear();\n    //sunlightNodes.clear();\n    //tertiaryDataNodes.clear();\n    // //   chunk->_blockIDContainer.initFromSortedArray()\n\n    //ui16 blockID;\n    //ui16 lampLight;\n    //ui8 sunlight;\n    //ui16 tertiaryData;\n\n    ////Add first nodes\n    //blockIDNodes.push_back(IntervalTree<ui16>::LNode(0, 1, _blockIDBuffer[0]));\n    //lampLightNodes.push_back(IntervalTree<ui16>::LNode(0, 1, _lampLightBuffer[0]));\n    //sunlightNodes.push_back(IntervalTree<ui8>::LNode(0, 1, _sunlightBuffer[0]));\n    //tertiaryDataNodes.push_back(IntervalTree<ui16>::LNode(0, 1, _tertiaryDataBuffer[0]));\n\n    ////Construct the node vectors\n    //for (int i = 1; i < CHUNK_SIZE; i++) {\n    //    blockID = _blockIDBuffer[i];\n    //    lampLight = _lampLightBuffer[i];\n    //    sunlight = _sunlightBuffer[i];\n    //    tertiaryData = _tertiaryDataBuffer[i];\n\n    //    if (blockID != 0) chunk->numBlocks++;\n    //    \n    //    if (GETBLOCK(blockID).spawnerVal || GETBLOCK(blockID).sinkVal){\n    //        chunk->spawnerBlocks.push_back(i);\n    //    }\n\n    //    if (blockID == blockIDNodes.back().data) {\n    //        blockIDNodes.back().length++;\n    //    } else {\n    //        blockIDNodes.push_back(IntervalTree<ui16>::LNode(i, 1, blockID));\n    //    }\n    //    if (lampLight == lampLightNodes.back().data) {\n    //        lampLightNodes.back().length++;\n    //    } else {\n    //        lampLightNodes.push_back(IntervalTree<ui16>::LNode(i, 1, lampLight));\n    //    }\n    //    if (sunlight == sunlightNodes.back().data) {\n    //        sunlightNodes.back().length++;\n    //    } else {\n    //        sunlightNodes.push_back(IntervalTree<ui8>::LNode(i, 1, sunlight));\n    //    }\n    //    if (tertiaryData == tertiaryDataNodes.back().data) {\n    //        tertiaryDataNodes.back().length++;\n    //    } else {\n    //        tertiaryDataNodes.push_back(IntervalTree<ui16>::LNode(i, 1, tertiaryData));\n    //    }\n    //}\n  \n    //chunk->_blockIDContainer.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, blockIDNodes);\n    //chunk->_lampLightContainer.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, lampLightNodes);\n    //chunk->_sunlightContainer.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, sunlightNodes);\n    //chunk->_tertiaryDataContainer.initFromSortedArray(vvox::VoxelStorageState::INTERVAL_TREE, tertiaryDataNodes);\n\n    return true;\n}\n\n//Saves the header for the region file\nbool RegionFileManager::saveRegionHeader() {\n    //Go back to beginning of file to save the header\n    if (!seek(0)) {\n        pError(\"Fseek error: could not seek to start. Save file is corrupted!\\n\");\n        return false;\n    }\n    //Save the header\n    if (fwrite(&(_regionFile->header), 1, sizeof(RegionFileHeader), _regionFile->file) != sizeof(RegionFileHeader)){\n        pError(\"Region write error: could not write loc buffer. Save file is corrupted!\\n\");\n        return false;\n    }\n\n    _regionFile->isHeaderDirty = false;\n\n    return true;\n}\n\n//Loads the header for the region file and stores it in the region file class\nbool RegionFileManager::loadRegionHeader() {\n\n    if (!seek(0)){\n        pError(\"Region fseek error F could not seek to start\\n\");\n        return false;\n    }\n    if (fread(&(_regionFile->header), 1, sizeof(RegionFileHeader), _regionFile->file) != sizeof(RegionFileHeader)){ //read the whole buffer in\n        pError(\"Region read error: could not read region header\\n\");\n        return false;\n    }\n\n    return true;\n}\n\nvoid RegionFileManager::rleCompressArray(ui8* data, int jStart, int jMult, int jEnd, int jInc, int kStart, int kMult, int kEnd, int kInc) {\n    int count = 1;\n    int tot = 0;\n    ui16 curr = data[jStart*jMult + kStart*kMult];\n    int index;\n    int z = 0;\n    bool first = true;\n    for (int i = 0; i < CHUNK_WIDTH; i++){ //y\n        for (int j = jStart; j != jEnd; j += jInc){ //z\n            for (int k = kStart; k != kEnd; k += kInc){ //x \n                z++;\n                if (!first) {\n                    index = i*CHUNK_LAYER + j*jMult + k*kMult;\n                    if (data[index] != curr){\n                        _chunkBuffer[_bufferSize++] = (ui8)(count & 0xFF);\n                        _chunkBuffer[_bufferSize++] = (ui8)((count & 0xFF00) >> 8);\n                        _chunkBuffer[_bufferSize++] = (ui8)curr;\n                        tot += count;\n\n                        curr = data[index];\n                        count = 1;\n                    } else{\n                        count++;\n                    }\n                } else {\n                    first = false;\n                }\n            }\n        }\n    }\n    _chunkBuffer[_bufferSize++] = (ui8)(count & 0xFF);\n    _chunkBuffer[_bufferSize++] = (ui8)((count & 0xFF00) >> 8);\n    tot += count;\n    _chunkBuffer[_bufferSize++] = (ui8)curr;\n}\n\nvoid RegionFileManager::rleCompressArray(ui16* data, int jStart, int jMult, int jEnd, int jInc, int kStart, int kMult, int kEnd, int kInc) {\n    int count = 1;\n    ui16 curr = data[jStart*jMult + kStart*kMult];\n    int index;\n    int tot = 0;\n    bool first = true;\n    for (int i = 0; i < CHUNK_WIDTH; i++){ //y\n        for (int j = jStart; j != jEnd; j += jInc){ //z\n            for (int k = kStart; k != kEnd; k += kInc){ //x \n                if (!first){\n                    index = i*CHUNK_LAYER + j*jMult + k*kMult;\n                    if (data[index] != curr){\n                        _chunkBuffer[_bufferSize++] = (ui8)(count & 0xFF);\n                        _chunkBuffer[_bufferSize++] = (ui8)((count & 0xFF00) >> 8);\n                        _chunkBuffer[_bufferSize++] = (ui8)(curr & 0xFF);\n                        _chunkBuffer[_bufferSize++] = (ui8)((curr & 0xFF00) >> 8);                   \n                        tot += count;\n                        curr = data[index];\n                        count = 1;\n                    } else{\n                        count++;\n                    }\n                } else{\n                    first = false;\n                }\n            }\n        }\n    }\n    _chunkBuffer[_bufferSize++] = (ui8)(count & 0xFF);\n    _chunkBuffer[_bufferSize++] = (ui8)((count & 0xFF00) >> 8);\n    _chunkBuffer[_bufferSize++] = (ui8)(curr & 0xFF);\n    _chunkBuffer[_bufferSize++] = (ui8)((curr & 0xFF00) >> 8);\n    tot += count;\n}\n\nbool RegionFileManager::rleCompressChunk(Chunk* chunk VORB_UNUSED) {\n\n    // TODO(Ben): Fix\n\n    //ui16* blockIDData;\n    //ui8* sunlightData;\n    //ui16* lampLightData;\n    //ui16* tertiaryData;\n\n    ////Need to lock so that nobody modifies the interval tree out from under us\n    //chunk->lock();\n    //if (chunk->_blockIDContainer.getState() == vvox::VoxelStorageState::INTERVAL_TREE) {\n    //    blockIDData = _blockIDBuffer;\n    //    chunk->_blockIDContainer.uncompressIntoBuffer(blockIDData);\n    //} else {\n    //    blockIDData = chunk->_blockIDContainer.getDataArray();\n    //}\n    //if (chunk->_lampLightContainer.getState() == vvox::VoxelStorageState::INTERVAL_TREE) {\n    //    lampLightData = _lampLightBuffer;\n    //    chunk->_lampLightContainer.uncompressIntoBuffer(lampLightData);\n    //} else {\n    //    lampLightData = chunk->_lampLightContainer.getDataArray();\n    //}\n    //if (chunk->_sunlightContainer.getState() == vvox::VoxelStorageState::INTERVAL_TREE) {\n    //    sunlightData = _sunlightBuffer;\n    //    chunk->_sunlightContainer.uncompressIntoBuffer(sunlightData);\n    //} else {\n    //    sunlightData = chunk->_sunlightContainer.getDataArray();\n    //}\n    //if (chunk->_tertiaryDataContainer.getState() == vvox::VoxelStorageState::INTERVAL_TREE) {\n    //    tertiaryData = _tertiaryDataBuffer;\n    //    chunk->_tertiaryDataContainer.uncompressIntoBuffer(tertiaryData);\n    //} else {\n    //    tertiaryData = chunk->_tertiaryDataContainer.getDataArray();\n    //}\n    //chunk->unlock();\n\n    //_bufferSize = 0;\n\n    //// Set the tag\n    //memcpy(_chunkBuffer, TAG_VOXELDATA_STR, 4);\n    //_bufferSize += 4;\n\n    //int jStart, jEnd, jInc;\n    //int kStart, kEnd, kInc;\n    //int jMult, kMult;\n\n    //chunk->voxelMapData->getIterationConstants(jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc);\n\n    //rleCompressArray(blockIDData, jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc);\n    //rleCompressArray(lampLightData, jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc);\n    //rleCompressArray(sunlightData, jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc);\n    //rleCompressArray(tertiaryData, jStart, jMult, jEnd, jInc, kStart, kMult, kEnd, kInc);\n\n    return true;\n}\n\nbool RegionFileManager::zlibCompress() {\n    _compressedBufferSize = CHUNK_DATA_SIZE + CHUNK_SIZE * 2;\n    //Compress the data, and leave space for the uncompressed chunk header\n    int zresult = compress2(_compressedByteBuffer + sizeof(ChunkHeader), &_compressedBufferSize, _chunkBuffer, _bufferSize, 6);\n    _compressedBufferSize += sizeof(ChunkHeader);\n\n    return (!checkZlibError(\"compression\", zresult));\n}\n\n// TODO: Implement this and remove VORB_UNUSED tags.\nbool RegionFileManager::tryConvertSave(ui32 regionVersion VORB_UNUSED) {\n    pError(\"Invalid region file version!\");\n    return false;\n}\n\n//Writes sector data, be sure to fseek to the correct position first\nbool RegionFileManager::writeSectors(ui8* srcBuffer, ui32 size) {\n\n    if (size % SECTOR_SIZE) {\n        ui32 padLength = SECTOR_SIZE - size % SECTOR_SIZE;\n        if (padLength == SECTOR_SIZE) padLength = 0;\n        size += padLength;\n    }\n\n    if (fwrite(srcBuffer, 1, size, _regionFile->file) != size) {\n        pError(\"Chunk Saving: Did not write enough bytes at A \" + std::to_string(size));\n        return false;\n    }\n    return true;\n}\n\n//Read sector data, be sure to fseek to the correct position first\nbool RegionFileManager::readSectors(ui8* dstBuffer, ui32 size) {\n    if (fread(dstBuffer, 1, size, _regionFile->file) != size) {\n        pError(\"Chunk Loading: Did not read enough bytes at A \" + std::to_string(size) + \" \" + std::to_string(_regionFile->totalSectors));\n        return false;\n    }\n    return true;\n}\n\nbool RegionFileManager::seek(ui32 byteOffset) {\n    return (fseek(_regionFile->file, byteOffset, SEEK_SET) == 0);\n}\n\nbool RegionFileManager::seekToChunk(ui32 chunkSectorOffset) {\n    //seek to the chunk\n    return seek(sizeof(RegionFileHeader) + chunkSectorOffset * SECTOR_SIZE);\n}\n\nui32 RegionFileManager::getChunkSectorOffset(Chunk* chunk VORB_UNUSED, ui32* retTableOffset VORB_UNUSED) {\n    \n    //const ChunkPosition3D& gridPos = chunk->gridPosition;\n\n    //int x = gridPos.pos.x % REGION_WIDTH;\n    //int y = gridPos.pos.y % REGION_WIDTH;\n    //int z = gridPos.pos.z % REGION_WIDTH;\n\n    ////modulus is weird in c++ for negative numbers\n    //if (x < 0) x += REGION_WIDTH;\n    //if (y < 0) y += REGION_WIDTH;\n    //if (z < 0) z += REGION_WIDTH;\n    //ui32 tableOffset = 4 * (x + z * REGION_WIDTH + y * REGION_LAYER);\n\n    ////If the caller asked for the table offset, return it\n    //if (retTableOffset) *retTableOffset = tableOffset;\n\n    //return BufferUtils::extractInt(_regionFile->header.lookupTable, tableOffset);\n    return 0;\n}\n\nnString RegionFileManager::getRegionString(Chunk *ch)\n{\n    const ChunkPosition3D& gridPos = ch->getChunkPosition();\n\n    return \"r.\" + std::to_string(fastFloor((float)gridPos.pos.x / REGION_WIDTH)) + \".\"\n        + std::to_string(fastFloor((float)gridPos.pos.y / REGION_WIDTH)) + \".\"\n        + std::to_string(fastFloor((float)gridPos.pos.z / REGION_WIDTH));\n}"
  },
  {
    "path": "SoA/RegionFileManager.h",
    "content": "#pragma once\n#include <deque>\n#include <map>\n\n#include <zconf.h>\n#include <Vorb/Vorb.h>\n\n#include \"Constants.h\"\n#include \"VoxelCoordinateSpaces.h\"\n\n//Size of a sector in bytes\n#define SECTOR_SIZE 512\n\n//Make sure REGION_WIDTH is 2 ^ RSHIFT and\n//REGION_SIZE is REGION_WIDTH ^ 3 and\n//REGION_LAYER is REGION_WIDTH ^ 2\n#define RSHIFT 4\n#define REGION_WIDTH 16\n#define REGION_LAYER 256\n#define REGION_SIZE 4096\n\n#define REGION_VER_0 1000\n\n#define CURRENT_REGION_VER REGION_VER_0\n\n#define CHUNK_DATA_SIZE (CHUNK_SIZE * 4) //right now a voxel is 4 bytes\n\n#define COMPRESSION_RLE 0x1\n#define COMPRESSION_ZLIB 0x10\n\n//All data is stored in byte arrays so we can force it to be saved in big-endian\nclass ChunkHeader {\npublic:\n    ui8 compression[4];\n    ui8 timeStamp[4];\n    ui8 dataLength[4]; //length of the data\n};\n\nclass RegionFileHeader {\npublic:\n    ui8 lookupTable[REGION_SIZE * 4];\n};\n\nclass RegionFile {\npublic:\n    RegionFileHeader header;\n    nString region;\n    FILE* file;\n    int fileDescriptor;\n    i32 totalSectors;\n    bool isHeaderDirty;\n};\n\nclass SaveVersion {\npublic:\n    ui8 regionVersion[4];\n    ui8 chunkVersion[4];\n};\n\nclass Chunk;\n\nclass RegionFileManager {\npublic:\n    RegionFileManager(const nString& saveDir);\n    ~RegionFileManager();\n\n    void clear();\n\n    bool openRegionFile(nString region, const ChunkPosition3D& gridPosition, bool create);\n\n    bool tryLoadChunk(Chunk* chunk);\n    bool saveChunk(Chunk* chunk);\n\n    void flush();\n\n    bool saveVersionFile();\n    bool checkVersion();\nprivate:\n    void closeRegionFile(RegionFile* regionFile);\n\n    bool readChunkHeader();\n    bool readChunkData_v0();\n\n    int rleUncompressArray(ui8* data, ui32& byteIndex, int jStart, int jMult, int jEnd, int jInc, int kStart, int kMult, int kEnd, int kInc);\n    int rleUncompressArray(ui16* data, ui32& byteIndex, int jStart, int jMult, int jEnd, int jInc, int kStart, int kMult, int kEnd, int kInc);\n    bool fillChunkVoxelData(Chunk* chunk);\n\n    bool saveRegionHeader();\n    bool loadRegionHeader();\n\n    void rleCompressArray(ui8* data, int jStart, int jMult, int jEnd, int jInc, int kStart, int kMult, int kEnd, int kInc);\n    void rleCompressArray(ui16* data, int jStart, int jMult, int jEnd, int jInc, int kStart, int kMult, int kEnd, int kInc);\n    bool rleCompressChunk(Chunk* chunk);\n    bool zlibCompress();\n\n    bool tryConvertSave(ui32 regionVersion);\n\n    bool writeSectors(ui8* srcBuffer, ui32 size);\n    bool readSectors(ui8* dstBuffer, ui32 size);\n\n    bool seek(ui32 byteOffset);\n    bool seekToChunk(ui32 chunkSectorOffset);\n\n    ui32 getChunkSectorOffset(Chunk* chunk, ui32* retTableOffset = nullptr);\n    nString getRegionString(Chunk* chunk);\n    \n    //Byte buffer for reading chunk data\n    ui32 _bufferSize;\n    ui8 _chunkBuffer[CHUNK_DATA_SIZE];\n    //Byte buffer for compressed data. It is slightly larger because of worst case with RLE\n    uLongf _compressedBufferSize;\n    ui8 _compressedByteBuffer[CHUNK_DATA_SIZE + CHUNK_SIZE * 4 + sizeof(ChunkHeader)];\n    //Dynamic byte buffer used in copying contents of a file for resize\n//    ui32 _copySectorsBufferSize;\n    ui8* _copySectorsBuffer;\n\n//    ui16 _blockIDBuffer[CHUNK_SIZE];\n//    ui8 _sunlightBuffer[CHUNK_SIZE];\n//    ui16 _lampLightBuffer[CHUNK_SIZE];\n//    ui16 _tertiaryDataBuffer[CHUNK_SIZE];\n\n//    ui8 _chunkHeaderBuffer[sizeof(ChunkHeader)];\n//    ui8 _regionFileHeaderBuffer[sizeof(RegionFileHeader)];\n    \n    ui32 _maxCacheSize;\n//    ui32 _chunkOffset; ///< Offset into the chunk data\n    uLongf _chunkBufferSize;\n    std::map <nString, RegionFile*> _regionFileCache;\n    std::deque <RegionFile*> _regionFileCacheQueue;\n\n    nString m_saveDir;\n    RegionFile* _regionFile;\n    ChunkHeader _chunkHeader;\n};"
  },
  {
    "path": "SoA/RenderUtils.h",
    "content": "///\n/// RenderUtils.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 3 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Some simple utils for rendering\n///\n\n#pragma once\n\n#ifndef RenderUtils_h__\n#define RenderUtils_h__\n\n#include \"stdafx.h\"\n\n/// Sets translation for a matrix relative to relativePos. Will overwrite existing translation\ninline void setMatrixTranslation(f32m4& matrix, const f64v3 &position, const f64v3& relativePos) {\n    matrix[3][0] = (f32)(position.x - relativePos.x);\n    matrix[3][1] = (f32)(position.y - relativePos.y);\n    matrix[3][2] = (f32)(position.z - relativePos.z);\n}\n\n/// Sets translation for a matrix relative to relativePos. Will overwrite existing translation\ninline void setMatrixTranslation(f32m4& matrix, const f32v3 &position, const f32v3& relativePos) {\n    matrix[3][0] = (position.x - relativePos.x);\n    matrix[3][1] = (position.y - relativePos.y);\n    matrix[3][2] = (position.z - relativePos.z);\n}\n\n/// Sets translation for a matrix relative to relativePos. Will overwrite existing translation\ninline void setMatrixTranslation(f32m4& matrix, const f32v3 &position, const f64v3& relativePos) {\n    matrix[3][0] = (f32)((f64)position.x - relativePos.x);\n    matrix[3][1] = (f32)((f64)position.y - relativePos.y);\n    matrix[3][2] = (f32)((f64)position.z - relativePos.z);\n}\n\n/// Sets translation for a matrix. Will overwrite existing translation\ninline void setMatrixTranslation(f32m4& matrix, const f32 x, const f32 y, const f32 z) {\n    matrix[3][0] = x;\n    matrix[3][1] = y;\n    matrix[3][2] = z;\n}\n\n/// Sets translation for a matrix. Will overwrite existing translation\ninline void setMatrixTranslation(f32m4& matrix, const double x, const double y, const double z) {\n    matrix[3][0] = (f32)x;\n    matrix[3][1] = (f32)y;\n    matrix[3][2] = (f32)z;\n}\n\n/// Sets translation for a matrix. Will overwrite existing translation\ninline void setMatrixTranslation(f32m4& matrix, const f32v3& trans) {\n    matrix[3][0] = trans.x;\n    matrix[3][1] = trans.y;\n    matrix[3][2] = trans.z;\n}\n\n/// Sets translation for a matrix. Will overwrite existing translation\ninline void setMatrixTranslation(f32m4& matrix, const f64v3& trans) {\n    matrix[3][0] = (f32)trans.x;\n    matrix[3][1] = (f32)trans.y;\n    matrix[3][2] = (f32)trans.z;\n}\n\n/// Sets scale for a matrix. Will overwrite existing scale\ninline void setMatrixScale(f32m4& matrix, const f32v3 &scale) {\n    matrix[0][0] = scale.x;\n    matrix[1][1] = scale.y;\n    matrix[2][2] = scale.z;\n}\n\n/// Sets scale for a matrix. Will overwrite existing scale\ninline void setMatrixScale(f32m4& matrix, const f32 scaleX, const f32 scaleY, const f32 scaleZ) {\n    matrix[0][0] = scaleX;\n    matrix[1][1] = scaleY;\n    matrix[2][2] = scaleZ;\n}\n\n#endif // RenderUtils_h__"
  },
  {
    "path": "SoA/Resources/resources.rc",
    "content": "MAINICON ICON DISCARDABLE \"SOA.ico\""
  },
  {
    "path": "SoA/SOA.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" DefaultTargets=\"Build\" ToolsVersion=\"14.0\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"DebugXP|Win32\">\n      <Configuration>DebugXP</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"DebugXP|x64\">\n      <Configuration>DebugXP</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseXP|Win32\">\n      <Configuration>ReleaseXP</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"ReleaseXP|x64\">\n      <Configuration>ReleaseXP</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{588491F3-69BA-40E7-8CE8-2382A64D86E3}</ProjectGuid>\n    <RootNamespace>soa</RootNamespace>\n    <ProjectName>SoA</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140_xp</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140_xp</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <IncludePath>$(SolutionDir)deps\\win32\\include;$(SolutionDir);$(SolutionDir)deps\\include;$(IncludePath)</IncludePath>\n    <LibraryPath>$(SolutionDir)deps\\win32\\lib;$(LibraryPath)</LibraryPath>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n    <TargetName>SoA</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|Win32'\">\n    <IncludePath>$(SolutionDir)deps\\win32\\include;$(SolutionDir);$(SolutionDir)deps\\include;$(IncludePath)</IncludePath>\n    <LibraryPath>$(SolutionDir)deps\\win32\\lib;$(LibraryPath)</LibraryPath>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n    <TargetName>SoA</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <IncludePath>$(SolutionDir)deps\\win32\\include;$(IncludePath)</IncludePath>\n    <LibraryPath>$(SolutionDir)deps\\win32\\lib;$(SolutionDir)bin\\lib\\$(PlatformName)\\$(PlatformTarget)\\$(Configuration)\\;$(LibraryPath)</LibraryPath>\n    <IntDir>$(Configuration)</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(PlatformTarget)\\$(Configuration)\\</OutDir>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);</LibraryPath>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n    <TargetName>SoA</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|Win32'\">\n    <IncludePath>$(SolutionDir)deps\\win32\\include;$(IncludePath)</IncludePath>\n    <LibraryPath>$(SolutionDir)deps\\win32\\lib;$(SolutionDir)bin\\lib\\$(PlatformName)\\$(PlatformTarget)\\$(Configuration)\\;$(LibraryPath)</LibraryPath>\n    <IntDir>$(Configuration)</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(PlatformTarget)\\$(Configuration)\\</OutDir>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);</LibraryPath>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n    <TargetName>SoA</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <TargetName>SoA</TargetName>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);</LibraryPath>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|x64'\">\n    <TargetName>SoA</TargetName>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);</LibraryPath>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);</LibraryPath>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <TargetName>SoA</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|Win32'\">\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);</LibraryPath>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <TargetName>SoA</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <TargetName>SoA</TargetName>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);</LibraryPath>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|x64'\">\n    <TargetName>SoA</TargetName>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>\n    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);</LibraryPath>\n    <OutDir>$(SolutionDir)bin\\$(PlatformName)\\$(Configuration)\\SoA\\</OutDir>\n    <IntDir>$(SolutionDir)obj\\$(PlatformName)\\$(Configuration)\\SoA\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>$(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>VORB_USING_PCH;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;DEBUG;VORB_IMPL_GRAPHICS_OPENGL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions>VORB_USING_PCH;VORB_USING_SCRIPT;VORB_IMPL_GRAPHICS_OPENGL;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <ForcedIncludeFiles>\n      </ForcedIncludeFiles>\n      <PreprocessToFile>false</PreprocessToFile>\n      <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>\n      <AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <MinimalRebuild>true</MinimalRebuild>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Vorb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Console</SubSystem>\n      <LargeAddressAware>true</LargeAddressAware>\n      <AdditionalLibraryDirectories>$(SolutionDir)deps\\lib\\$(PlatformName)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <PostBuildEvent>\n      <Command>robocopy /XO /E \"$(SolutionDir)deps\\dll\\$(PlatformName)\\$(Configuration)\\ \" \"$(OutDir) \" * /XD \".git\"\nEXIT 0</Command>\n      <Message>Copying dependencies to output directory</Message>\n    </PostBuildEvent>\n    <PreBuildEvent>\n      <Command>cd $(SolutionDir)\n$(SolutionDir)VorbCopy.bat</Command>\n    </PreBuildEvent>\n    <PreBuildEvent>\n      <Message>Run the Vorb copy script</Message>\n    </PreBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>$(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>VORB_USING_PCH;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;DEBUG;VORB_IMPL_GRAPHICS_OPENGL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PreprocessorDefinitions>VORB_USING_PCH;VORB_USING_SCRIPT;VORB_IMPL_GRAPHICS_OPENGL;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;DEBUG;XP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <ForcedIncludeFiles>\n      </ForcedIncludeFiles>\n      <PreprocessToFile>false</PreprocessToFile>\n      <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>\n      <AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <MinimalRebuild>true</MinimalRebuild>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Vorb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Console</SubSystem>\n      <LargeAddressAware>true</LargeAddressAware>\n      <AdditionalLibraryDirectories>$(SolutionDir)deps\\lib\\$(PlatformName)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <PostBuildEvent>\n      <Command>robocopy /XO /E \"$(SolutionDir)deps\\dll\\$(PlatformName)\\$(Configuration)\\ \" \"$(OutDir) \" * /XD \".git\"\nEXIT 0</Command>\n      <Message>Copying dependencies to output directory</Message>\n    </PostBuildEvent>\n    <PreBuildEvent>\n      <Command>cd $(SolutionDir)\n$(SolutionDir)VorbCopy.bat</Command>\n    </PreBuildEvent>\n    <PreBuildEvent>\n      <Message>Run the Vorb copy script</Message>\n    </PreBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>$(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>VORB_USING_PCH;VORB_USING_SCRIPT;VORB_IMPL_GRAPHICS_OPENGL;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <ForcedIncludeFiles>\n      </ForcedIncludeFiles>\n      <PreprocessToFile>false</PreprocessToFile>\n      <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>\n      <AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Vorb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Console</SubSystem>\n      <LargeAddressAware>true</LargeAddressAware>\n      <AdditionalLibraryDirectories>$(SolutionDir)deps\\lib\\$(PlatformName)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <PostBuildEvent>\n      <Command>robocopy /XO /E \"$(SolutionDir)deps\\dll\\$(PlatformName)\\$(Configuration)\\ \" \"$(OutDir) \" * /XD \".git\"\nEXIT 0</Command>\n      <Message>Copying dependencies to output directory</Message>\n    </PostBuildEvent>\n    <PreBuildEvent>\n      <Command>cd $(SolutionDir)\n$(SolutionDir)VorbCopy.bat</Command>\n    </PreBuildEvent>\n    <PreBuildEvent>\n      <Message>Run the Vorb copy script</Message>\n    </PreBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>$(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>VORB_USING_PCH;VORB_USING_SCRIPT;VORB_IMPL_GRAPHICS_OPENGL;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <ForcedIncludeFiles>\n      </ForcedIncludeFiles>\n      <PreprocessToFile>false</PreprocessToFile>\n      <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>\n      <AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Vorb-d.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Console</SubSystem>\n      <LargeAddressAware>true</LargeAddressAware>\n      <AdditionalLibraryDirectories>$(SolutionDir)deps\\lib\\$(PlatformName)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <PostBuildEvent>\n      <Command>robocopy /XO /E \"$(SolutionDir)deps\\dll\\$(PlatformName)\\$(Configuration)\\ \" \"$(OutDir) \" * /XD \".git\"\nEXIT 0</Command>\n      <Message>Copying dependencies to output directory</Message>\n    </PostBuildEvent>\n    <PreBuildEvent>\n      <Command>cd $(SolutionDir)\n$(SolutionDir)VorbCopy.bat</Command>\n    </PreBuildEvent>\n    <PreBuildEvent>\n      <Message>Run the Vorb copy script</Message>\n    </PreBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <PreprocessorDefinitions>VORB_USING_PCH;VORB_USING_SCRIPT;VORB_IMPL_GRAPHICS_OPENGL;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <ForcedIncludeFiles>\n      </ForcedIncludeFiles>\n      <PreprocessToFile>false</PreprocessToFile>\n      <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n      <AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>Vorb.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Console</SubSystem>\n      <AdditionalLibraryDirectories>$(SolutionDir)deps\\lib\\$(PlatformName)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <LargeAddressAware>true</LargeAddressAware>\n      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n    </Link>\n    <PostBuildEvent>\n      <Command>robocopy /XO /E \"$(SolutionDir)deps\\dll\\$(PlatformName)\\$(Configuration)\\ \" \"$(OutDir) \" * /XD \".git\"\nEXIT 0</Command>\n      <Message>Copying dependencies to output directory</Message>\n    </PostBuildEvent>\n    <PreBuildEvent>\n      <Command>cd $(SolutionDir)\n$(SolutionDir)VorbCopy.bat</Command>\n    </PreBuildEvent>\n    <PreBuildEvent>\n      <Message>Run the Vorb copy script</Message>\n    </PreBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <PreprocessorDefinitions>VORB_USING_PCH;VORB_USING_SCRIPT;VORB_IMPL_GRAPHICS_OPENGL;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;NDEBUG;XP;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <ForcedIncludeFiles>\n      </ForcedIncludeFiles>\n      <PreprocessToFile>false</PreprocessToFile>\n      <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n      <AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>Vorb.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Console</SubSystem>\n      <AdditionalLibraryDirectories>$(SolutionDir)deps\\lib\\$(PlatformName)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <LargeAddressAware>true</LargeAddressAware>\n      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n    </Link>\n    <PostBuildEvent>\n      <Command>robocopy /XO /E \"$(SolutionDir)deps\\dll\\$(PlatformName)\\$(Configuration)\\ \" \"$(OutDir) \" * /XD \".git\"\nEXIT 0</Command>\n      <Message>Copying dependencies to output directory</Message>\n    </PostBuildEvent>\n    <PreBuildEvent>\n      <Command>cd $(SolutionDir)\n$(SolutionDir)VorbCopy.bat</Command>\n    </PreBuildEvent>\n    <PreBuildEvent>\n      <Message>Run the Vorb copy script</Message>\n    </PreBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <PreprocessorDefinitions>VORB_USING_PCH;VORB_USING_SCRIPT;VORB_IMPL_GRAPHICS_OPENGL;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <ForcedIncludeFiles>\n      </ForcedIncludeFiles>\n      <PreprocessToFile>false</PreprocessToFile>\n      <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n      <AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>Vorb.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Console</SubSystem>\n      <AdditionalLibraryDirectories>$(SolutionDir)deps\\lib\\$(PlatformName)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <LargeAddressAware>true</LargeAddressAware>\n      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n    </Link>\n    <PostBuildEvent>\n      <Command>robocopy /XO /E \"$(SolutionDir)deps\\dll\\$(PlatformName)\\$(Configuration)\\ \" \"$(OutDir) \" * /XD \".git\"\nEXIT 0</Command>\n      <Message>Copying dependencies to output directory</Message>\n    </PostBuildEvent>\n    <PreBuildEvent>\n      <Command>cd $(SolutionDir)\n$(SolutionDir)VorbCopy.bat</Command>\n    </PreBuildEvent>\n    <PreBuildEvent>\n      <Message>Run the Vorb copy script</Message>\n    </PreBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>$(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <PreprocessorDefinitions>VORB_USING_PCH;VORB_USING_SCRIPT;VORB_IMPL_GRAPHICS_OPENGL;BT_USE_DOUBLE_PRECISION;WINDOWS;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <ForcedUsingFiles>\n      </ForcedUsingFiles>\n      <ForcedIncludeFiles>\n      </ForcedIncludeFiles>\n      <PreprocessToFile>false</PreprocessToFile>\n      <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>\n      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n      <AdditionalOptions>-D_SCL_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>Vorb.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <SubSystem>Console</SubSystem>\n      <AdditionalLibraryDirectories>$(SolutionDir)deps\\lib\\$(PlatformName)\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <LargeAddressAware>true</LargeAddressAware>\n      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n    </Link>\n    <PostBuildEvent>\n      <Command>robocopy /XO /E \"$(SolutionDir)deps\\dll\\$(PlatformName)\\$(Configuration)\\ \" \"$(OutDir) \" * /XD \".git\"\nEXIT 0</Command>\n      <Message>Copying dependencies to output directory</Message>\n    </PostBuildEvent>\n    <PreBuildEvent>\n      <Command>cd $(SolutionDir)\n$(SolutionDir)VorbCopy.bat</Command>\n    </PreBuildEvent>\n    <PreBuildEvent>\n      <Message>Run the Vorb copy script</Message>\n    </PreBuildEvent>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"AABBCollidableComponentUpdater.h\" />\n    <ClInclude Include=\"AmbienceLibrary.h\" />\n    <ClInclude Include=\"AmbiencePlayer.h\" />\n    <ClInclude Include=\"AmbienceStream.h\" />\n    <ClInclude Include=\"Animation.h\" />\n    <ClInclude Include=\"ChunkAccessor.h\" />\n    <ClInclude Include=\"ChunkID.h\" />\n    <ClInclude Include=\"ChunkQuery.h\" />\n    <ClInclude Include=\"ChunkSphereComponentUpdater.h\" />\n    <ClInclude Include=\"ClientState.h\" />\n    <ClInclude Include=\"ConsoleTests.h\" />\n    <ClInclude Include=\"Density.h\" />\n    <ClInclude Include=\"DLLAPI.h\" />\n    <ClInclude Include=\"ARProcessor.h\" />\n    <ClInclude Include=\"AtmosphereComponentRenderer.h\" />\n    <ClInclude Include=\"AxisRotationComponentUpdater.h\" />\n    <ClInclude Include=\"Biome.h\" />\n    <ClInclude Include=\"BlockPack.h\" />\n    <ClInclude Include=\"BlockTexture.h\" />\n    <ClInclude Include=\"BlockTextureMethods.h\" />\n    <ClInclude Include=\"BlockTexturePack.h\" />\n    <ClInclude Include=\"BloomRenderStage.h\" />\n    <ClInclude Include=\"CellularAutomataTask.h\" />\n    <ClInclude Include=\"ChunkAllocator.h\" />\n    <ClInclude Include=\"ChunkGridRenderStage.h\" />\n    <ClInclude Include=\"ChunkHandle.h\" />\n    <ClInclude Include=\"ChunkMeshManager.h\" />\n    <ClInclude Include=\"ChunkMeshTask.h\" />\n    <ClInclude Include=\"CommonState.h\" />\n    <ClInclude Include=\"CloudsComponentRenderer.h\" />\n    <ClInclude Include=\"CollisionComponentUpdater.h\" />\n    <ClInclude Include=\"ColoredFullQuadRenderer.h\" />\n    <ClInclude Include=\"ColorFilterRenderStage.h\" />\n    <ClInclude Include=\"Computer.h\" />\n    <ClInclude Include=\"ConsoleFuncs.h\" />\n    <ClInclude Include=\"ConsoleMain.h\" />\n    <ClInclude Include=\"DLLLoader.h\" />\n    <ClInclude Include=\"DualContouringMesher.h\" />\n    <ClInclude Include=\"ECSTemplates.h\" />\n    <ClInclude Include=\"FarTerrainComponentRenderer.h\" />\n    <ClInclude Include=\"FarTerrainComponentUpdater.h\" />\n    <ClInclude Include=\"FarTerrainPatch.h\" />\n    <ClInclude Include=\"Flora.h\" />\n    <ClInclude Include=\"FrustumComponentUpdater.h\" />\n    <ClInclude Include=\"CutoutVoxelRenderStage.h\" />\n    <ClInclude Include=\"DevHudRenderStage.h\" />\n    <ClInclude Include=\"GameplayLoadScreen.h\" />\n    <ClInclude Include=\"GameplayRenderer.h\" />\n    <ClInclude Include=\"GameplayScreen.h\" />\n    <ClInclude Include=\"GameRenderParams.h\" />\n    <ClInclude Include=\"GameSystem.h\" />\n    <ClInclude Include=\"GameSystemComponentBuilders.h\" />\n    <ClInclude Include=\"GameSystemComponents.h\" />\n    <ClInclude Include=\"GameSystemAssemblages.h\" />\n    <ClInclude Include=\"GameSystemUpdater.h\" />\n    <ClInclude Include=\"GasGiantComponentRenderer.h\" />\n    <ClInclude Include=\"HdrRenderStage.h\" />\n    <ClInclude Include=\"BlockLoader.h\" />\n    <ClInclude Include=\"HeadComponentUpdater.h\" />\n    <ClInclude Include=\"ImageAssetLoader.h\" />\n    <ClInclude Include=\"IRenderStage.h\" />\n    <ClInclude Include=\"LenseFlareRenderer.h\" />\n    <ClInclude Include=\"LiquidVoxelRenderStage.h\" />\n    <ClInclude Include=\"LoadContext.h\" />\n    <ClInclude Include=\"LoadTaskBlockData.h\" />\n    <ClInclude Include=\"LoadTaskStarSystem.h\" />\n    <ClInclude Include=\"LoadTaskTextures.h\" />\n    <ClInclude Include=\"ExposureCalcRenderStage.h\" />\n    <ClInclude Include=\"MainMenuRenderer.h\" />\n    <ClInclude Include=\"MainMenuScreen.h\" />\n    <ClInclude Include=\"MainMenuScriptedUI.h\" />\n    <ClInclude Include=\"MainMenuSystemViewer.h\" />\n    <ClInclude Include=\"MarchingCubesTable.h\" />\n    <ClInclude Include=\"ModelMesher.h\" />\n    <ClInclude Include=\"MetaSection.h\" />\n    <ClInclude Include=\"ModInformation.h\" />\n    <ClInclude Include=\"ModPathResolver.h\" />\n    <ClInclude Include=\"MTRenderState.h\" />\n    <ClInclude Include=\"MTRenderStateManager.h\" />\n    <ClInclude Include=\"MusicPlayer.h\" />\n    <ClInclude Include=\"BlockTextureLoader.h\" />\n    <ClInclude Include=\"Chunk.h\" />\n    <ClInclude Include=\"ChunkGrid.h\" />\n    <ClInclude Include=\"FloraGenerator.h\" />\n    <ClInclude Include=\"NightVisionRenderStage.h\" />\n    <ClInclude Include=\"Noise.h\" />\n    <ClInclude Include=\"NoiseShaderCode.hpp\" />\n    <ClInclude Include=\"Octree.h\" />\n    <ClInclude Include=\"OpaqueVoxelRenderStage.h\" />\n    <ClInclude Include=\"OptionsController.h\" />\n    <ClInclude Include=\"OrbitComponentRenderer.h\" />\n    <ClInclude Include=\"OrbitComponentUpdater.h\" />\n    <ClInclude Include=\"ParkourComponentUpdater.h\" />\n    <ClInclude Include=\"PauseMenu.h\" />\n    <ClInclude Include=\"PauseMenuRenderStage.h\" />\n    <ClInclude Include=\"PDA.h\" />\n    <ClInclude Include=\"PdaRenderStage.h\" />\n    <ClInclude Include=\"PhysicsBlockRenderStage.h\" />\n    <ClInclude Include=\"PhysicsComponentUpdater.h\" />\n    <ClInclude Include=\"PlanetGenData.h\" />\n    <ClInclude Include=\"PlanetGenerator.h\" />\n    <ClInclude Include=\"PlanetHeightData.h\" />\n    <ClInclude Include=\"PlanetGenLoader.h\" />\n    <ClInclude Include=\"PlanetRingsComponentRenderer.h\" />\n    <ClInclude Include=\"Positional.h\" />\n    <ClInclude Include=\"ProceduralChunkGenerator.h\" />\n    <ClInclude Include=\"ProgramGenDelegate.h\" />\n    <ClInclude Include=\"qef.h\" />\n    <ClInclude Include=\"ShaderAssetLoader.h\" />\n    <ClInclude Include=\"ShaderLoader.h\" />\n    <ClInclude Include=\"SkyboxRenderer.h\" />\n    <ClInclude Include=\"SoaController.h\" />\n    <ClInclude Include=\"SoaEngine.h\" />\n    <ClInclude Include=\"SoaState.h\" />\n    <ClInclude Include=\"SoaFileSystem.h\" />\n    <ClInclude Include=\"soaUtils.h\" />\n    <ClInclude Include=\"SonarRenderStage.h\" />\n    <ClInclude Include=\"SkyboxRenderStage.h\" />\n    <ClInclude Include=\"SpaceSystem.h\" />\n    <ClInclude Include=\"SpaceSystemComponentBuilders.h\" />\n    <ClInclude Include=\"SpaceSystemComponents.h\" />\n    <ClInclude Include=\"SpaceSystemAssemblages.h\" />\n    <ClInclude Include=\"SpaceSystemLoader.h\" />\n    <ClInclude Include=\"SpaceSystemLoadStructs.h\" />\n    <ClInclude Include=\"SpaceSystemRenderStage.h\" />\n    <ClInclude Include=\"SpaceSystemUpdater.h\" />\n    <ClInclude Include=\"SphericalTerrainComponentRenderer.h\" />\n    <ClInclude Include=\"SphericalTerrainComponentUpdater.h\" />\n    <ClInclude Include=\"SphericalHeightmapGenerator.h\" />\n    <ClInclude Include=\"SSAORenderStage.h\" />\n    <ClInclude Include=\"StarComponentRenderer.h\" />\n    <ClInclude Include=\"Startup.h\" />\n    <ClInclude Include=\"svd.h\" />\n    <ClInclude Include=\"SystemARRenderer.h\" />\n    <ClInclude Include=\"SystemBodyLoader.h\" />\n    <ClInclude Include=\"TerrainPatchMeshManager.h\" />\n    <ClInclude Include=\"SpaceSystemComponentTables.h\" />\n    <ClInclude Include=\"SphericalVoxelComponentUpdater.h\" />\n    <ClInclude Include=\"TerrainGenTextures.h\" />\n    <ClInclude Include=\"TerrainPatchMesher.h\" />\n    <ClInclude Include=\"TerrainPatchConstants.h\" />\n    <ClInclude Include=\"TerrainPatchMesh.h\" />\n    <ClInclude Include=\"TerrainPatchMeshTask.h\" />\n    <ClInclude Include=\"TestBiomeScreen.h\" />\n    <ClInclude Include=\"TestBlockViewScreen.h\" />\n    <ClInclude Include=\"TestConnectedTextureScreen.h\" />\n    <ClInclude Include=\"TestConsoleScreen.h\" />\n    <ClInclude Include=\"TestDeferredScreen.h\" />\n    <ClInclude Include=\"TestDisplacementMappingScreen.h\" />\n    <ClInclude Include=\"TestGasGiantScreen.h\" />\n    <ClInclude Include=\"TestMappingScreen.h\" />\n    <ClInclude Include=\"TestVoxelModelScreen.h\" />\n    <ClInclude Include=\"TestNoiseScreen.h\" />\n    <ClInclude Include=\"TestNewBlockAPIScreen.h\" />\n    <ClInclude Include=\"TestPlanetGenScreen.h\" />\n    <ClInclude Include=\"TestStarScreen.h\" />\n    <ClInclude Include=\"textureUtils.h\" />\n    <ClInclude Include=\"TransparentVoxelRenderStage.h\" />\n    <ClInclude Include=\"InitScreen.h\" />\n    <ClInclude Include=\"LoadMonitor.h\" />\n    <ClInclude Include=\"VoxelBits.h\" />\n    <ClInclude Include=\"VoxelCoordinateSpaces.h\" />\n    <ClInclude Include=\"VoxelMatrix.h\" />\n    <ClInclude Include=\"VoxelMesh.h\" />\n    <ClInclude Include=\"VoxelMesher.h\" />\n    <ClInclude Include=\"ChunkGenerator.h\" />\n    <ClInclude Include=\"ChunkMesh.h\" />\n    <ClInclude Include=\"ChunkRenderer.h\" />\n    <ClInclude Include=\"DevConsole.h\" />\n    <ClInclude Include=\"DevConsoleView.h\" />\n    <ClInclude Include=\"ChunkUpdater.h\" />\n    <ClInclude Include=\"GeometrySorter.h\" />\n    <ClInclude Include=\"SmartVoxelContainer.hpp\" />\n    <ClInclude Include=\"LiquidData.h\" />\n    <ClInclude Include=\"LoadBar.h\" />\n    <ClInclude Include=\"MainMenuLoadScreen.h\" />\n    <ClInclude Include=\"CAEngine.h\" />\n    <ClInclude Include=\"ChunkMesher.h\" />\n    <ClInclude Include=\"DebugRenderer.h\" />\n    <ClInclude Include=\"FragFile.h\" />\n    <ClInclude Include=\"Item.h\" />\n    <ClInclude Include=\"TextureAtlas.h\" />\n    <ClInclude Include=\"TextureData.h\" />\n    <ClInclude Include=\"TextureStack.h\" />\n    <ClInclude Include=\"ParticleMesh.h\" />\n    <ClInclude Include=\"RegionFileManager.h\" />\n    <ClInclude Include=\"stdafx.h\" />\n    <ClInclude Include=\"App.h\" />\n    <ClInclude Include=\"VoxelEditor.h\" />\n    <ClInclude Include=\"VoxelLightEngine.h\" />\n    <ClInclude Include=\"VoxelModel.h\" />\n    <ClInclude Include=\"VoxelModelLoader.h\" />\n    <ClInclude Include=\"VoxelModelMesh.h\" />\n    <ClInclude Include=\"VoxelModelRenderer.h\" />\n    <ClInclude Include=\"VoxelNavigation.inl\" />\n    <ClInclude Include=\"VoxelNodeSetter.h\" />\n    <ClInclude Include=\"VoxelNodeSetterTask.h\" />\n    <ClInclude Include=\"VoxelSpaceConversions.h\" />\n    <ClInclude Include=\"VoxelSpaceUtils.h\" />\n    <ClInclude Include=\"VoxelUpdateBufferer.h\" />\n    <ClInclude Include=\"VoxelUtils.h\" />\n    <ClInclude Include=\"VoxelVertices.h\" />\n    <ClInclude Include=\"VoxPool.h\" />\n    <ClInclude Include=\"WSO.h\" />\n    <ClInclude Include=\"WSOAtlas.h\" />\n    <ClInclude Include=\"WSOScanner.h\" />\n    <ClInclude Include=\"WSOData.h\" />\n    <ClInclude Include=\"Inputs.h\" />\n    <ClInclude Include=\"InputMapper.h\" />\n    <ClInclude Include=\"atomicops.h\" />\n    <ClInclude Include=\"BlockData.h\" />\n    <ClInclude Include=\"Camera.h\" />\n    <ClInclude Include=\"Collision.h\" />\n    <ClInclude Include=\"Constants.h\" />\n    <ClInclude Include=\"Errors.h\" />\n    <ClInclude Include=\"Frustum.h\" />\n    <ClInclude Include=\"GameManager.h\" />\n    <ClInclude Include=\"GenerateTask.h\" />\n    <ClInclude Include=\"RenderUtils.h\" />\n    <ClInclude Include=\"TerrainPatch.h\" />\n    <ClInclude Include=\"Vertex.h\" />\n    <ClInclude Include=\"SoaOptions.h\" />\n    <ClInclude Include=\"readerwriterqueue.h\" />\n    <ClInclude Include=\"VoxelRay.h\" />\n    <ClInclude Include=\"VRayHelper.h\" />\n    <ClInclude Include=\"ChunkIOManager.h\" />\n    <ClInclude Include=\"WorldStructs.h\" />\n    <ClInclude Include=\"ZipFile.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"AABBCollidableComponentUpdater.cpp\" />\n    <ClCompile Include=\"AmbienceLibrary.cpp\" />\n    <ClCompile Include=\"AmbiencePlayer.cpp\" />\n    <ClCompile Include=\"AmbienceStream.cpp\" />\n    <ClCompile Include=\"ARProcessor.cpp\" />\n    <ClCompile Include=\"AtmosphereComponentRenderer.cpp\" />\n    <ClCompile Include=\"AxisRotationComponentUpdater.cpp\" />\n    <ClCompile Include=\"Biome.cpp\" />\n    <ClCompile Include=\"BlockPack.cpp\" />\n    <ClCompile Include=\"BlockTexture.cpp\" />\n    <ClCompile Include=\"BlockTextureLoader.cpp\" />\n    <ClCompile Include=\"BlockTextureMethods.cpp\" />\n    <ClCompile Include=\"BlockTexturePack.cpp\" />\n    <ClCompile Include=\"BloomRenderStage.cpp\" />\n    <ClCompile Include=\"CellularAutomataTask.cpp\" />\n    <ClCompile Include=\"ChunkAccessor.cpp\" />\n    <ClCompile Include=\"ChunkAllocator.cpp\" />\n    <ClCompile Include=\"ChunkGridRenderStage.cpp\" />\n    <ClCompile Include=\"ChunkMeshManager.cpp\" />\n    <ClCompile Include=\"ChunkMeshTask.cpp\" />\n    <ClCompile Include=\"ChunkQuery.cpp\" />\n    <ClCompile Include=\"ChunkSphereComponentUpdater.cpp\" />\n    <ClCompile Include=\"CloudsComponentRenderer.cpp\" />\n    <ClCompile Include=\"CollisionComponentUpdater.cpp\" />\n    <ClCompile Include=\"ColoredFullQuadRenderer.cpp\" />\n    <ClCompile Include=\"ColorFilterRenderStage.cpp\" />\n    <ClCompile Include=\"Computer.cpp\" />\n    <ClCompile Include=\"ConsoleFuncs.cpp\" />\n    <ClCompile Include=\"ConsoleMain.cpp\" />\n    <ClCompile Include=\"ConsoleTests.cpp\" />\n    <ClCompile Include=\"CutoutVoxelRenderStage.cpp\" />\n    <ClCompile Include=\"Density.cpp\" />\n    <ClCompile Include=\"DevHudRenderStage.cpp\" />\n    <ClCompile Include=\"DevScreen.cpp\" />\n    <ClCompile Include=\"DualContouringMesher.cpp\" />\n    <ClCompile Include=\"ECSTemplates.cpp\" />\n    <ClCompile Include=\"FarTerrainComponentRenderer.cpp\" />\n    <ClCompile Include=\"FarTerrainComponentUpdater.cpp\" />\n    <ClCompile Include=\"FarTerrainPatch.cpp\" />\n    <ClCompile Include=\"Flora.cpp\" />\n    <ClCompile Include=\"FrustumComponentUpdater.cpp\" />\n    <ClCompile Include=\"GameplayLoadScreen.cpp\" />\n    <ClCompile Include=\"GameplayRenderer.cpp\" />\n    <ClCompile Include=\"GameplayScreen.cpp\" />\n    <ClCompile Include=\"GameRenderParams.cpp\" />\n    <ClCompile Include=\"GameSystem.cpp\" />\n    <ClCompile Include=\"GameSystemAssemblages.cpp\" />\n    <ClCompile Include=\"GameSystemComponentBuilders.cpp\" />\n    <ClCompile Include=\"GameSystemComponents.cpp\" />\n    <ClCompile Include=\"GameSystemUpdater.cpp\" />\n    <ClCompile Include=\"GasGiantComponentRenderer.cpp\" />\n    <ClCompile Include=\"GenerateTask.cpp\" />\n    <ClCompile Include=\"HdrRenderStage.cpp\" />\n    <ClCompile Include=\"BlockLoader.cpp\" />\n    <ClCompile Include=\"HeadComponentUpdater.cpp\" />\n    <ClCompile Include=\"ImageAssetLoader.cpp\" />\n    <ClCompile Include=\"Item.cpp\" />\n    <ClCompile Include=\"LenseFlareRenderer.cpp\" />\n    <ClCompile Include=\"LiquidVoxelRenderStage.cpp\" />\n    <ClCompile Include=\"ExposureCalcRenderStage.cpp\" />\n    <ClCompile Include=\"MainMenuRenderer.cpp\" />\n    <ClCompile Include=\"MainMenuScreen.cpp\" />\n    <ClCompile Include=\"InitScreen.cpp\" />\n    <ClCompile Include=\"LoadMonitor.cpp\" />\n    <ClCompile Include=\"MainMenuScriptedUI.cpp\" />\n    <ClCompile Include=\"MainMenuSystemViewer.cpp\" />\n    <ClCompile Include=\"ModelMesher.cpp\" />\n    <ClCompile Include=\"MetaSection.cpp\" />\n    <ClCompile Include=\"ModPathResolver.cpp\" />\n    <ClCompile Include=\"MTRenderStateManager.cpp\" />\n    <ClCompile Include=\"MusicPlayer.cpp\" />\n    <ClCompile Include=\"Chunk.cpp\" />\n    <ClCompile Include=\"ChunkGrid.cpp\" />\n    <ClCompile Include=\"FloraGenerator.cpp\" />\n    <ClCompile Include=\"NightVisionRenderStage.cpp\" />\n    <ClCompile Include=\"Noise.cpp\" />\n    <ClCompile Include=\"Octree.cpp\" />\n    <ClCompile Include=\"OpaqueVoxelRenderStage.cpp\" />\n    <ClCompile Include=\"OptionsController.cpp\" />\n    <ClCompile Include=\"OrbitComponentRenderer.cpp\" />\n    <ClCompile Include=\"OrbitComponentUpdater.cpp\" />\n    <ClCompile Include=\"ParkourComponentUpdater.cpp\" />\n    <ClCompile Include=\"PauseMenu.cpp\" />\n    <ClCompile Include=\"PauseMenuRenderStage.cpp\" />\n    <ClCompile Include=\"PDA.cpp\" />\n    <ClCompile Include=\"PdaRenderStage.cpp\" />\n    <ClCompile Include=\"PhysicsBlockRenderStage.cpp\" />\n    <ClCompile Include=\"PhysicsComponentUpdater.cpp\" />\n    <ClCompile Include=\"PlanetGenData.cpp\" />\n    <ClCompile Include=\"PlanetGenerator.cpp\" />\n    <ClCompile Include=\"PlanetGenLoader.cpp\" />\n    <ClCompile Include=\"PlanetRingsComponentRenderer.cpp\" />\n    <ClCompile Include=\"ProceduralChunkGenerator.cpp\" />\n    <ClCompile Include=\"qef.cpp\" />\n    <ClCompile Include=\"ShaderAssetLoader.cpp\" />\n    <ClCompile Include=\"ShaderLoader.cpp\" />\n    <ClCompile Include=\"SkyboxRenderer.cpp\" />\n    <ClCompile Include=\"SoaController.cpp\" />\n    <ClCompile Include=\"SoaEngine.cpp\" />\n    <ClCompile Include=\"SoaState.cpp\" />\n    <ClCompile Include=\"SoaFileSystem.cpp\" />\n    <ClCompile Include=\"SonarRenderStage.cpp\" />\n    <ClCompile Include=\"SkyboxRenderStage.cpp\" />\n    <ClCompile Include=\"FreeMoveComponentUpdater.cpp\" />\n    <ClCompile Include=\"SpaceSystem.cpp\" />\n    <ClCompile Include=\"SpaceSystemAssemblages.cpp\" />\n    <ClCompile Include=\"SpaceSystemComponentBuilders.cpp\" />\n    <ClCompile Include=\"SpaceSystemLoader.cpp\" />\n    <ClCompile Include=\"SpaceSystemLoadStructs.cpp\" />\n    <ClCompile Include=\"SpaceSystemRenderStage.cpp\" />\n    <ClCompile Include=\"SpaceSystemUpdater.cpp\" />\n    <ClCompile Include=\"SphericalTerrainComponentRenderer.cpp\" />\n    <ClCompile Include=\"SphericalTerrainComponentUpdater.cpp\" />\n    <ClCompile Include=\"SphericalHeightmapGenerator.cpp\" />\n    <ClCompile Include=\"SSAORenderStage.cpp\" />\n    <ClCompile Include=\"StarComponentRenderer.cpp\" />\n    <ClCompile Include=\"Startup.cpp\" />\n    <ClCompile Include=\"svd.cpp\" />\n    <ClCompile Include=\"SystemARRenderer.cpp\" />\n    <ClCompile Include=\"SystemBodyLoader.cpp\" />\n    <ClCompile Include=\"TerrainPatchMeshManager.cpp\" />\n    <ClCompile Include=\"SpaceSystemComponentTables.cpp\" />\n    <ClCompile Include=\"SphericalVoxelComponentUpdater.cpp\" />\n    <ClCompile Include=\"TerrainGenTextures.cpp\" />\n    <ClCompile Include=\"TerrainPatchMesher.cpp\" />\n    <ClCompile Include=\"TerrainPatchMesh.cpp\" />\n    <ClCompile Include=\"TerrainPatchMeshTask.cpp\" />\n    <ClCompile Include=\"TestBiomeScreen.cpp\" />\n    <ClCompile Include=\"TestBlockViewScreen.cpp\" />\n    <ClCompile Include=\"TestConnectedTextureScreen.cpp\" />\n    <ClCompile Include=\"TestConsoleScreen.cpp\" />\n    <ClCompile Include=\"TestDeferredScreen.cpp\" />\n    <ClCompile Include=\"TestDisplacementMappingScreen.cpp\" />\n    <ClCompile Include=\"TestGasGiantScreen.cpp\" />\n    <ClCompile Include=\"TestMappingScreen.cpp\" />\n    <ClCompile Include=\"TestVoxelModelScreen.cpp\" />\n    <ClCompile Include=\"TestNoiseScreen.cpp\" />\n    <ClCompile Include=\"TestNewBlockAPIScreen.cpp\" />\n    <ClCompile Include=\"TestPlanetGenScreen.cpp\" />\n    <ClCompile Include=\"TestStarScreen.cpp\" />\n    <ClCompile Include=\"TransparentVoxelRenderStage.cpp\" />\n    <ClCompile Include=\"VoxelMatrix.cpp\" />\n    <ClCompile Include=\"VoxelMesher.cpp\" />\n    <ClCompile Include=\"ChunkGenerator.cpp\" />\n    <ClCompile Include=\"ChunkMesh.cpp\" />\n    <ClCompile Include=\"ChunkRenderer.cpp\" />\n    <ClCompile Include=\"ChunkUpdater.cpp\" />\n    <ClCompile Include=\"DevConsole.cpp\" />\n    <ClCompile Include=\"DevConsoleView.cpp\" />\n    <ClCompile Include=\"GeometrySorter.cpp\" />\n    <ClCompile Include=\"LoadBar.cpp\" />\n    <ClCompile Include=\"MainMenuLoadScreen.cpp\" />\n    <ClCompile Include=\"CAEngine.cpp\" />\n    <ClCompile Include=\"DebugRenderer.cpp\" />\n    <ClCompile Include=\"FragFile.cpp\" />\n    <ClCompile Include=\"InputMapper.cpp\" />\n    <ClCompile Include=\"BlockData.cpp\" />\n    <ClCompile Include=\"Camera.cpp\" />\n    <ClCompile Include=\"Inputs.cpp\" />\n    <ClCompile Include=\"RegionFileManager.cpp\" />\n    <ClCompile Include=\"stdafx.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='DebugXP|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='ReleaseXP|x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"App.cpp\" />\n    <ClCompile Include=\"VoxelEditor.cpp\" />\n    <ClCompile Include=\"VoxelLightEngine.cpp\" />\n    <ClCompile Include=\"VoxelModel.cpp\" />\n    <ClCompile Include=\"VoxelModelLoader.cpp\" />\n    <ClCompile Include=\"VoxelModelMesh.cpp\" />\n    <ClCompile Include=\"VoxelModelRenderer.cpp\" />\n    <ClCompile Include=\"VoxelNodeSetter.cpp\" />\n    <ClCompile Include=\"VoxelNodeSetterTask.cpp\" />\n    <ClCompile Include=\"VoxelRay.cpp\" />\n    <ClCompile Include=\"VoxelSpaceConversions.cpp\" />\n    <ClCompile Include=\"VoxelSpaceUtils.cpp\" />\n    <ClCompile Include=\"VoxPool.cpp\" />\n    <ClCompile Include=\"VRayHelper.cpp\" />\n    <ClCompile Include=\"ChunkIOManager.cpp\" />\n    <ClCompile Include=\"ChunkMesher.cpp\" />\n    <ClCompile Include=\"Collision.cpp\" />\n    <ClCompile Include=\"Errors.cpp\" />\n    <ClCompile Include=\"Frustum.cpp\" />\n    <ClCompile Include=\"GameManager.cpp\" />\n    <ClCompile Include=\"TerrainPatch.cpp\" />\n    <ClCompile Include=\"main.cpp\" />\n    <ClCompile Include=\"SoaOptions.cpp\" />\n    <ClCompile Include=\"WorldStructs.cpp\" />\n    <ClCompile Include=\"WSO.cpp\" />\n    <ClCompile Include=\"WSOAtlas.cpp\" />\n    <ClCompile Include=\"WSOScanner.cpp\" />\n    <ClCompile Include=\"ZipFile.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"Resources\\resources.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Resources\\SOA.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"docs\\FileSpecs\\WSO.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"VirtualKeyKegDef.inl\" />\n    <None Include=\"VoxelUpdateOrder.inl\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "SoA/SOA.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"SOA Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\">\n      <UniqueIdentifier>{525edd3f-153d-4d7e-b2c5-811fe8ece78b}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Generation\">\n      <UniqueIdentifier>{2c08331c-74a3-41e5-a2ae-d7f834b44a9c}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Meshing\">\n      <UniqueIdentifier>{47d2e9d3-5782-498b-8946-54c76c398ccd}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Tasking\">\n      <UniqueIdentifier>{a64b4a4f-cf12-45af-bea5-915fe1edb71f}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Utils\">\n      <UniqueIdentifier>{3b6faecb-6048-43b9-b958-0ec1519bcfd4}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\WSO\">\n      <UniqueIdentifier>{8004f8be-0c9d-4b46-8de3-95f601224cb7}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Ext\">\n      <UniqueIdentifier>{16458b45-378f-4940-9d6b-22626b459c7d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Ext\\Input\">\n      <UniqueIdentifier>{bdc5c7ad-0882-4888-bf85-a2b6df8ca6c8}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Ext\\ADT\">\n      <UniqueIdentifier>{69183acd-97b7-4ccf-8b3d-bf869213d785}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\">\n      <UniqueIdentifier>{6ed11451-4fd0-4e0b-bb3d-7c837c30e6b0}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\UI\">\n      <UniqueIdentifier>{c500d35d-e264-4ecb-91ae-63e32462a5f5}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\Wrappers\">\n      <UniqueIdentifier>{28e31f12-788f-4d75-83c4-90578c32fd26}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\Images\">\n      <UniqueIdentifier>{944280de-51d1-4204-8783-de9d490e0597}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\">\n      <UniqueIdentifier>{006799fc-14f6-4bb3-9ba5-ce6e1a519f66}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Objects\">\n      <UniqueIdentifier>{cf258b53-3a8a-47e2-bff3-cfe5f3bcd843}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Objects\\Materials\">\n      <UniqueIdentifier>{b2f9c117-3cdf-4c36-9025-eab0f43b9857}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Physics\">\n      <UniqueIdentifier>{66e53e02-b172-41ff-9611-8bc3bb0cc2e6}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Particles\">\n      <UniqueIdentifier>{41066a19-1d18-4603-a153-87d0e8ee97c3}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Data\">\n      <UniqueIdentifier>{d0120966-37e8-471d-bdce-519b4af45baf}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Sound\">\n      <UniqueIdentifier>{a6444217-9b9d-47d7-93ef-b7677b135940}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Data\\IO Utils\">\n      <UniqueIdentifier>{f13fbb0d-44a4-47c5-ab3e-37ea49ff2371}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\">\n      <UniqueIdentifier>{f1c18989-f573-4fa6-ba8b-ebcaa46f53d1}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\\Load\">\n      <UniqueIdentifier>{6da0d3a4-a60f-4ed2-804e-c655cc23292d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\">\n      <UniqueIdentifier>{27b0b7c0-0ccd-46a8-be5f-bace1ed61570}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Dev\">\n      <UniqueIdentifier>{f94617d8-52f7-4073-97a5-2d26439a6c08}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\Dev\">\n      <UniqueIdentifier>{a8613ee5-a6ad-4b60-8567-0a15bb9ae82c}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Mapping\">\n      <UniqueIdentifier>{f10c4941-dfe2-4bfb-a029-a82ec2a097dd}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\\Init\">\n      <UniqueIdentifier>{27507245-c888-4a05-b0ca-9890d99db1a2}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\\Menu\">\n      <UniqueIdentifier>{0d210193-9560-40f1-a16b-af80064b7293}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Tools\">\n      <UniqueIdentifier>{da75023d-4b8b-4790-af72-c6535569b583}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\RenderPipelines\">\n      <UniqueIdentifier>{09cebf8a-9329-4dea-aac4-4d56d9dd2f37}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\RenderPipelines\\RenderStages\">\n      <UniqueIdentifier>{ed09a071-ec97-4fd2-922b-f2c36eba05dc}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Tools\\AR\">\n      <UniqueIdentifier>{853856ea-242e-44d2-8339-eaf88777864f}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Universe\">\n      <UniqueIdentifier>{22a36be7-1c86-4e53-bdde-77f979115e26}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\\Dev\">\n      <UniqueIdentifier>{877c328b-8bd7-4523-952d-f4bbb6408408}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\\Test\">\n      <UniqueIdentifier>{07d56bf0-8858-45a6-bcf5-6fe4f58dc323}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\\StarSystem\">\n      <UniqueIdentifier>{1c1faa8a-6bbf-4bd3-a594-ba162a1a31a9}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\\Components\">\n      <UniqueIdentifier>{9ca22bd9-7b16-4f82-914d-635a6afa8e69}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\\Updaters\">\n      <UniqueIdentifier>{85765d6e-8575-45fa-82db-357787c61b39}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\\Systems\">\n      <UniqueIdentifier>{73eeb8a0-c66a-4fc2-bd59-edcbe41b3993}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Sound\\Music\">\n      <UniqueIdentifier>{70862515-6514-4574-9caf-db361861ced8}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Sound\\Ambience\">\n      <UniqueIdentifier>{29e314c8-5ae6-4581-9595-811643a15e11}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\\ComponentTables\">\n      <UniqueIdentifier>{f52bd506-1a48-4733-81fd-e5ccf12ec387}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\\Assemblages\">\n      <UniqueIdentifier>{5a883327-0095-495a-b35f-f80c5fec3f94}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\\Updaters\\GameSystem\">\n      <UniqueIdentifier>{3786d69c-53eb-4f18-9fa3-f5b24d8dbfa1}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\\Updaters\\SpaceSystem\">\n      <UniqueIdentifier>{04e223d6-921c-418a-8fef-01869cbc81d1}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\Delegates\">\n      <UniqueIdentifier>{8ba56a3b-89be-47d4-a283-21b82f6ebbfa}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Game\\Universe\\Generation\">\n      <UniqueIdentifier>{f35809b6-67de-47ce-990b-6b313f00bfac}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\Universe\">\n      <UniqueIdentifier>{cbcce115-6609-45f8-8bf5-9f86d0c7358f}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\\Load\\Tasks\">\n      <UniqueIdentifier>{3d4b1864-12e0-42f6-93e0-9dd41f775f53}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Screens\\Gameplay\">\n      <UniqueIdentifier>{67ff73ec-bf0a-46da-a71d-8821a7acbd76}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Rendering\\Components\">\n      <UniqueIdentifier>{452e9a89-0e3d-42af-827a-14a1b726bc20}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Client\">\n      <UniqueIdentifier>{05a33879-3c8f-4d59-a153-cc3c410fcc98}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Client\\Asset\">\n      <UniqueIdentifier>{c4cbe6c3-81db-48d5-9680-8b949bc631a6}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\API\">\n      <UniqueIdentifier>{705cf454-4163-4629-a5a8-b8f21eceeea7}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Allocation\">\n      <UniqueIdentifier>{548ab1e5-861c-44a6-9081-0769265688b2}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Texturing\">\n      <UniqueIdentifier>{29e1a60e-9cde-4091-b045-d6c803be19ca}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Console\">\n      <UniqueIdentifier>{771788c4-8294-4b8d-b65c-616f4371e8c9}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Modding\">\n      <UniqueIdentifier>{65cf4844-1033-4e01-a560-63f43e8b3660}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Models\">\n      <UniqueIdentifier>{57f94b81-194d-4aa7-91bb-c4855307dd0e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\Voxel\\Access\">\n      <UniqueIdentifier>{7438a4f1-7ecc-4b92-bc2a-6865f0686297}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"SOA Files\\ECS\\ComponentBuilders\">\n      <UniqueIdentifier>{8abe075e-c1df-4773-9ffd-b200f0dd9087}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"App.h\">\n      <Filter>SOA Files\\Screens</Filter>\n    </ClInclude>\n    <ClInclude Include=\"atomicops.h\">\n      <Filter>SOA Files\\Ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"BlockData.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CAEngine.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Camera.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkGenerator.h\">\n      <Filter>SOA Files\\Voxel\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkIOManager.h\">\n      <Filter>SOA Files\\Data</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkMesher.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkRenderer.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkUpdater.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Collision.h\">\n      <Filter>SOA Files\\Game\\Physics</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Constants.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DebugRenderer.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DevConsole.h\">\n      <Filter>SOA Files\\Game\\Dev</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DevConsoleView.h\">\n      <Filter>SOA Files\\Rendering\\Dev</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Errors.h\">\n      <Filter>SOA Files\\Ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FragFile.h\">\n      <Filter>SOA Files\\Data\\IO Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Frustum.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameManager.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GeometrySorter.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Inputs.h\">\n      <Filter>SOA Files\\Ext\\Input</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LiquidData.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LoadBar.h\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ParticleMesh.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"readerwriterqueue.h\">\n      <Filter>SOA Files\\Ext\\ADT</Filter>\n    </ClInclude>\n    <ClInclude Include=\"RegionFileManager.h\">\n      <Filter>SOA Files\\Data</Filter>\n    </ClInclude>\n    <ClInclude Include=\"RenderUtils.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"stdafx.h\">\n      <Filter>SOA Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelEditor.h\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelLightEngine.h\">\n      <Filter>SOA Files\\Voxel\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelRay.h\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelUtils.h\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VRayHelper.h\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WorldStructs.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WSO.h\">\n      <Filter>SOA Files\\Voxel\\WSO</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WSOAtlas.h\">\n      <Filter>SOA Files\\Voxel\\WSO</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WSOData.h\">\n      <Filter>SOA Files\\Voxel\\WSO</Filter>\n    </ClInclude>\n    <ClInclude Include=\"WSOScanner.h\">\n      <Filter>SOA Files\\Voxel\\WSO</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ZipFile.h\">\n      <Filter>SOA Files\\Data\\IO Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkMesh.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelMesher.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LoadMonitor.h\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClInclude>\n    <ClInclude Include=\"InitScreen.h\">\n      <Filter>SOA Files\\Screens\\Init</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MainMenuScreen.h\">\n      <Filter>SOA Files\\Screens\\Menu</Filter>\n    </ClInclude>\n    <ClInclude Include=\"BlockLoader.h\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Animation.h\">\n      <Filter>SOA Files\\Rendering\\Wrappers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PDA.h\">\n      <Filter>SOA Files\\Game\\Tools</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Computer.h\">\n      <Filter>SOA Files\\Game\\Tools</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TransparentVoxelRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SonarRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"OpaqueVoxelRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LiquidVoxelRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CutoutVoxelRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameRenderParams.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"HdrRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SkyboxRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PdaRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DevHudRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelBits.h\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"BlockTextureMethods.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"NightVisionRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ARProcessor.h\">\n      <Filter>SOA Files\\Game\\Tools\\AR</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PhysicsBlockRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GenerateTask.h\">\n      <Filter>SOA Files\\Voxel\\Tasking</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkGridRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelNavigation.inl\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CellularAutomataTask.h\">\n      <Filter>SOA Files\\Voxel\\Tasking</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PauseMenu.h\">\n      <Filter>SOA Files\\Screens\\Gameplay</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PauseMenuRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxPool.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestConsoleScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestMappingScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestDeferredScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystemRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestBlockViewScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"BlockPack.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelMesh.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelVertices.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SmartVoxelContainer.hpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MainMenuSystemViewer.h\">\n      <Filter>SOA Files\\Screens\\Menu</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystem.h\">\n      <Filter>SOA Files\\ECS\\Systems</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameSystem.h\">\n      <Filter>SOA Files\\ECS\\Systems</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SoaController.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SoaEngine.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SoaState.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameSystemComponents.h\">\n      <Filter>SOA Files\\ECS\\Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MusicPlayer.h\">\n      <Filter>SOA Files\\Sound\\Music</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SoaFileSystem.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AmbienceLibrary.h\">\n      <Filter>SOA Files\\Sound\\Ambience</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AmbienceStream.h\">\n      <Filter>SOA Files\\Sound\\Ambience</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AmbiencePlayer.h\">\n      <Filter>SOA Files\\Sound\\Ambience</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystemComponents.h\">\n      <Filter>SOA Files\\ECS\\Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystemLoadStructs.h\">\n      <Filter>SOA Files\\ECS\\Systems</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameSystemAssemblages.h\">\n      <Filter>SOA Files\\ECS\\Assemblages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystemAssemblages.h\">\n      <Filter>SOA Files\\ECS\\Assemblages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AxisRotationComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CollisionComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FrustumComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameSystemUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"OrbitComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ParkourComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PhysicsComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystemUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SphericalTerrainComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SphericalVoxelComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelSpaceConversions.h\">\n      <Filter>SOA Files\\Voxel\\Mapping</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelCoordinateSpaces.h\">\n      <Filter>SOA Files\\Voxel\\Mapping</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelSpaceUtils.h\">\n      <Filter>SOA Files\\Voxel\\Mapping</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ProgramGenDelegate.h\">\n      <Filter>SOA Files\\Rendering\\Delegates</Filter>\n    </ClInclude>\n    <ClInclude Include=\"NoiseShaderCode.hpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TerrainGenTextures.h\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FarTerrainPatch.h\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FarTerrainComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TerrainPatchMesh.h\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SkyboxRenderer.h\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TerrainPatchConstants.h\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TerrainPatchMesher.h\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TerrainPatchMeshManager.h\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TerrainPatch.h\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"soaUtils.h\">\n      <Filter>SOA Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SystemARRenderer.h\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MTRenderState.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MTRenderStateManager.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkMeshManager.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestGasGiantScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LoadTaskStarSystem.h\">\n      <Filter>SOA Files\\Screens\\Load\\Tasks</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LoadTaskTextures.h\">\n      <Filter>SOA Files\\Screens\\Load\\Tasks</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameplayScreen.h\">\n      <Filter>SOA Files\\Screens\\Gameplay</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ColoredFullQuadRenderer.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ShaderLoader.h\">\n      <Filter>SOA Files\\Rendering\\Wrappers</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AtmosphereComponentRenderer.h\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FarTerrainComponentRenderer.h\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GasGiantComponentRenderer.h\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"OrbitComponentRenderer.h\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SphericalTerrainComponentRenderer.h\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystemComponentTables.h\">\n      <Filter>SOA Files\\ECS\\ComponentTables</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SoaOptions.h\">\n      <Filter>SOA Files\\Data</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestDisplacementMappingScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestStarScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CloudsComponentRenderer.h\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystemLoader.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LoadContext.h\">\n      <Filter>SOA Files\\Screens</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ImageAssetLoader.h\">\n      <Filter>SOA Files\\Client\\Asset</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ShaderAssetLoader.h\">\n      <Filter>SOA Files\\Client\\Asset</Filter>\n    </ClInclude>\n    <ClInclude Include=\"IRenderStage.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ExposureCalcRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ColorFilterRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CommonState.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MainMenuRenderer.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameplayRenderer.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MainMenuLoadScreen.h\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameplayLoadScreen.h\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestNoiseScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MetaSection.h\">\n      <Filter>SOA Files\\Voxel\\API</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestNewBlockAPIScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Positional.h\">\n      <Filter>SOA Files\\Voxel\\Mapping</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PlanetHeightData.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkAllocator.h\">\n      <Filter>SOA Files\\Voxel\\Allocation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ProceduralChunkGenerator.h\">\n      <Filter>SOA Files\\Voxel\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"BlockTexturePack.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Chunk.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkGrid.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Vertex.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestPlanetGenScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ModPathResolver.h\">\n      <Filter>SOA Files\\Data\\IO Utils</Filter>\n    </ClInclude>\n    <ClInclude Include=\"InputMapper.h\">\n      <Filter>SOA Files\\Ext\\Input</Filter>\n    </ClInclude>\n    <ClInclude Include=\"OptionsController.h\">\n      <Filter>SOA Files\\Data</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PlanetGenerator.h\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"StarComponentRenderer.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LenseFlareRenderer.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"BlockTexture.h\">\n      <Filter>SOA Files\\Voxel\\Texturing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"BlockTextureLoader.h\">\n      <Filter>SOA Files\\Voxel\\Texturing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TextureAtlas.h\">\n      <Filter>SOA Files\\Voxel\\Texturing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TextureData.h\">\n      <Filter>SOA Files\\Voxel\\Texturing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TextureStack.h\">\n      <Filter>SOA Files\\Voxel\\Texturing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MainMenuScriptedUI.h\">\n      <Filter>SOA Files\\Screens\\Menu</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PlanetRingsComponentRenderer.h\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Biome.h\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Startup.h\">\n      <Filter>SOA Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ConsoleMain.h\">\n      <Filter>SOA Files\\Console</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ConsoleFuncs.h\">\n      <Filter>SOA Files\\Console</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DLLAPI.h\">\n      <Filter>SOA Files\\Modding</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DLLLoader.h\">\n      <Filter>SOA Files\\Modding</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ModInformation.h\">\n      <Filter>SOA Files\\Modding</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TerrainPatchMeshTask.h\">\n      <Filter>SOA Files\\Voxel\\Tasking</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkMeshTask.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestConnectedTextureScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"LoadTaskBlockData.h\">\n      <Filter>SOA Files\\Screens\\Load\\Tasks</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SphericalHeightmapGenerator.h\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Noise.h\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PlanetGenData.h\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelModelLoader.h\">\n      <Filter>SOA Files\\Voxel\\Models</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelModel.h\">\n      <Filter>SOA Files\\Voxel\\Models</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelModelRenderer.h\">\n      <Filter>SOA Files\\Voxel\\Models</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelMatrix.h\">\n      <Filter>SOA Files\\Voxel\\Models</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DualContouringMesher.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MarchingCubesTable.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ModelMesher.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelModelMesh.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"BloomRenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Octree.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"svd.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"qef.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestVoxelModelScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SSAORenderStage.h\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SystemBodyLoader.h\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ECSTemplates.h\">\n      <Filter>SOA Files\\ECS</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GameSystemComponentBuilders.h\">\n      <Filter>SOA Files\\ECS\\ComponentBuilders</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SpaceSystemComponentBuilders.h\">\n      <Filter>SOA Files\\ECS\\ComponentBuilders</Filter>\n    </ClInclude>\n    <ClInclude Include=\"TestBiomeScreen.h\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PlanetGenLoader.h\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Flora.h\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FloraGenerator.h\">\n      <Filter>SOA Files\\Voxel\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkAccessor.h\">\n      <Filter>SOA Files\\Voxel\\Access</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkHandle.h\">\n      <Filter>SOA Files\\Voxel\\Access</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkQuery.h\">\n      <Filter>SOA Files\\Voxel\\Access</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkID.h\">\n      <Filter>SOA Files\\Voxel\\Access</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ConsoleTests.h\">\n      <Filter>SOA Files\\Console</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ChunkSphereComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ClientState.h\">\n      <Filter>SOA Files\\Client</Filter>\n    </ClInclude>\n    <ClInclude Include=\"HeadComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Density.h\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AABBCollidableComponentUpdater.h\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Item.h\">\n      <Filter>SOA Files\\Game\\Objects</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelNodeSetter.h\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelNodeSetterTask.h\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClInclude>\n    <ClInclude Include=\"VoxelUpdateBufferer.h\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClInclude>\n    <ClInclude Include=\"textureUtils.h\">\n      <Filter>SOA Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"App.cpp\">\n      <Filter>SOA Files\\Screens</Filter>\n    </ClCompile>\n    <ClCompile Include=\"BlockData.cpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CAEngine.cpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Camera.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkGenerator.cpp\">\n      <Filter>SOA Files\\Voxel\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkIOManager.cpp\">\n      <Filter>SOA Files\\Data</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkMesher.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkRenderer.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkUpdater.cpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Collision.cpp\">\n      <Filter>SOA Files\\Game\\Physics</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DebugRenderer.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DevConsole.cpp\">\n      <Filter>SOA Files\\Game\\Dev</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DevConsoleView.cpp\">\n      <Filter>SOA Files\\Rendering\\Dev</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Errors.cpp\">\n      <Filter>SOA Files\\Ext</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FragFile.cpp\">\n      <Filter>SOA Files\\Data\\IO Utils</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Frustum.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameManager.cpp\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GeometrySorter.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Inputs.cpp\">\n      <Filter>SOA Files\\Ext\\Input</Filter>\n    </ClCompile>\n    <ClCompile Include=\"LoadBar.cpp\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClCompile>\n    <ClCompile Include=\"main.cpp\">\n      <Filter>SOA Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"RegionFileManager.cpp\">\n      <Filter>SOA Files\\Data</Filter>\n    </ClCompile>\n    <ClCompile Include=\"stdafx.cpp\">\n      <Filter>SOA Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelEditor.cpp\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelLightEngine.cpp\">\n      <Filter>SOA Files\\Voxel\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelRay.cpp\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VRayHelper.cpp\">\n      <Filter>SOA Files\\Voxel\\Utils</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WorldStructs.cpp\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WSO.cpp\">\n      <Filter>SOA Files\\Voxel\\WSO</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WSOAtlas.cpp\">\n      <Filter>SOA Files\\Voxel\\WSO</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WSOScanner.cpp\">\n      <Filter>SOA Files\\Voxel\\WSO</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ZipFile.cpp\">\n      <Filter>SOA Files\\Data\\IO Utils</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkMesh.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelMesher.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"InitScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Init</Filter>\n    </ClCompile>\n    <ClCompile Include=\"LoadMonitor.cpp\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MainMenuScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Menu</Filter>\n    </ClCompile>\n    <ClCompile Include=\"BlockLoader.cpp\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PDA.cpp\">\n      <Filter>SOA Files\\Game\\Tools</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Computer.cpp\">\n      <Filter>SOA Files\\Game\\Tools</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CutoutVoxelRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"LiquidVoxelRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"OpaqueVoxelRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SonarRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TransparentVoxelRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"HdrRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SkyboxRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameRenderParams.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PdaRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DevHudRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"BlockTextureMethods.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"NightVisionRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ARProcessor.cpp\">\n      <Filter>SOA Files\\Game\\Tools\\AR</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PhysicsBlockRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GenerateTask.cpp\">\n      <Filter>SOA Files\\Voxel\\Tasking</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkGridRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CellularAutomataTask.cpp\">\n      <Filter>SOA Files\\Voxel\\Tasking</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PauseMenu.cpp\">\n      <Filter>SOA Files\\Screens\\Gameplay</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PauseMenuRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxPool.cpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DevScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Dev</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestConsoleScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestMappingScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestDeferredScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpaceSystemRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"BlockPack.cpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestBlockViewScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MainMenuSystemViewer.cpp\">\n      <Filter>SOA Files\\Screens\\Menu</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpaceSystem.cpp\">\n      <Filter>SOA Files\\ECS\\Systems</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SoaController.cpp\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SoaEngine.cpp\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SoaState.cpp\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MusicPlayer.cpp\">\n      <Filter>SOA Files\\Sound\\Music</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SoaFileSystem.cpp\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AmbienceLibrary.cpp\">\n      <Filter>SOA Files\\Sound\\Ambience</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AmbienceStream.cpp\">\n      <Filter>SOA Files\\Sound\\Ambience</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AmbiencePlayer.cpp\">\n      <Filter>SOA Files\\Sound\\Ambience</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpaceSystemLoadStructs.cpp\">\n      <Filter>SOA Files\\ECS\\Systems</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameSystemAssemblages.cpp\">\n      <Filter>SOA Files\\ECS\\Assemblages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpaceSystemAssemblages.cpp\">\n      <Filter>SOA Files\\ECS\\Assemblages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AxisRotationComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CollisionComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FreeMoveComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FrustumComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameSystemUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"OrbitComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ParkourComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PhysicsComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SphericalTerrainComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SphericalVoxelComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpaceSystemUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelSpaceConversions.cpp\">\n      <Filter>SOA Files\\Voxel\\Mapping</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelSpaceUtils.cpp\">\n      <Filter>SOA Files\\Voxel\\Mapping</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TerrainGenTextures.cpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FarTerrainPatch.cpp\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FarTerrainComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\SpaceSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TerrainPatchMesh.cpp\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SkyboxRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TerrainPatchMesher.cpp\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TerrainPatchMeshManager.cpp\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TerrainPatch.cpp\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SystemARRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MTRenderStateManager.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkMeshManager.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestGasGiantScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameplayScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Gameplay</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ColoredFullQuadRenderer.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"InputMapper.cpp\">\n      <Filter>SOA Files\\Ext\\Input</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ShaderLoader.cpp\">\n      <Filter>SOA Files\\Rendering\\Wrappers</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AtmosphereComponentRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FarTerrainComponentRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GasGiantComponentRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"OrbitComponentRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SphericalTerrainComponentRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpaceSystemComponentTables.cpp\">\n      <Filter>SOA Files\\ECS\\ComponentTables</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SoaOptions.cpp\">\n      <Filter>SOA Files\\Data</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestDisplacementMappingScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestStarScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CloudsComponentRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpaceSystemLoader.cpp\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ImageAssetLoader.cpp\">\n      <Filter>SOA Files\\Client\\Asset</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ShaderAssetLoader.cpp\">\n      <Filter>SOA Files\\Client\\Asset</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ColorFilterRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ExposureCalcRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MainMenuRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameplayRenderer.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MainMenuLoadScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameplayLoadScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Load</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MetaSection.cpp\">\n      <Filter>SOA Files\\Voxel\\API</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestNewBlockAPIScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkAllocator.cpp\">\n      <Filter>SOA Files\\Voxel\\Allocation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ProceduralChunkGenerator.cpp\">\n      <Filter>SOA Files\\Voxel\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"BlockTexturePack.cpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Chunk.cpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkGrid.cpp\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestPlanetGenScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"BlockTexture.cpp\">\n      <Filter>SOA Files\\Voxel\\Texturing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"BlockTextureLoader.cpp\">\n      <Filter>SOA Files\\Voxel\\Texturing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SsaoRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Startup.cpp\">\n      <Filter>SOA Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ConsoleMain.cpp\">\n      <Filter>SOA Files\\Console</Filter>\n    </ClCompile>\n    <ClCompile Include=\"LenseFlareRenderer.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MainMenuScriptedUI.cpp\">\n      <Filter>SOA Files\\Screens\\Menu</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ModPathResolver.cpp\">\n      <Filter>SOA Files\\Data\\IO Utils</Filter>\n    </ClCompile>\n    <ClCompile Include=\"OptionsController.cpp\">\n      <Filter>SOA Files\\Data</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PlanetGenerator.cpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"StarComponentRenderer.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PlanetRingsComponentRenderer.cpp\">\n      <Filter>SOA Files\\Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestNoiseScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Biome.cpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ConsoleFuncs.cpp\">\n      <Filter>SOA Files\\Console</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TerrainPatchMeshTask.cpp\">\n      <Filter>SOA Files\\Voxel\\Tasking</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkMeshTask.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestConnectedTextureScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SphericalHeightmapGenerator.cpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Noise.cpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PlanetGenData.cpp\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DualContouringMesher.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ModelMesher.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Octree.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelModelMesh.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelModel.cpp\">\n      <Filter>SOA Files\\Voxel\\Models</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelMatrix.cpp\">\n      <Filter>SOA Files\\Voxel\\Models</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelModelLoader.cpp\">\n      <Filter>SOA Files\\Voxel\\Models</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelModelRenderer.cpp\">\n      <Filter>SOA Files\\Voxel\\Models</Filter>\n    </ClCompile>\n    <ClCompile Include=\"BloomRenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"svd.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"qef.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestVoxelModelScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SSAORenderStage.cpp\">\n      <Filter>SOA Files\\Rendering\\RenderPipelines\\RenderStages</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SystemBodyLoader.cpp\">\n      <Filter>SOA Files\\Game</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameSystem.cpp\">\n      <Filter>SOA Files\\ECS\\Systems</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ECSTemplates.cpp\">\n      <Filter>SOA Files\\ECS</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameSystemComponentBuilders.cpp\">\n      <Filter>SOA Files\\ECS\\ComponentBuilders</Filter>\n    </ClCompile>\n    <ClCompile Include=\"SpaceSystemComponentBuilders.cpp\">\n      <Filter>SOA Files\\ECS\\ComponentBuilders</Filter>\n    </ClCompile>\n    <ClCompile Include=\"GameSystemComponents.cpp\">\n      <Filter>SOA Files\\ECS\\Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"TestBiomeScreen.cpp\">\n      <Filter>SOA Files\\Screens\\Test</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PlanetGenLoader.cpp\">\n      <Filter>SOA Files\\Game\\Universe</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Flora.cpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FloraGenerator.cpp\">\n      <Filter>SOA Files\\Voxel\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkAccessor.cpp\">\n      <Filter>SOA Files\\Voxel\\Access</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ConsoleTests.cpp\">\n      <Filter>SOA Files\\Console</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkQuery.cpp\">\n      <Filter>SOA Files\\Voxel\\Access</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ChunkSphereComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"HeadComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Density.cpp\">\n      <Filter>SOA Files\\Voxel\\Meshing</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AABBCollidableComponentUpdater.cpp\">\n      <Filter>SOA Files\\ECS\\Updaters\\GameSystem</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Item.cpp\">\n      <Filter>SOA Files\\Game\\Objects</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelNodeSetter.cpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClCompile>\n    <ClCompile Include=\"VoxelNodeSetterTask.cpp\">\n      <Filter>SOA Files\\Game\\Universe\\Generation</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"Resources\\resources.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Resources\\SOA.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"docs\\FileSpecs\\WSO.txt\">\n      <Filter>SOA Files\\Voxel\\WSO</Filter>\n    </Text>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"VoxelUpdateOrder.inl\">\n      <Filter>SOA Files\\Voxel</Filter>\n    </None>\n    <None Include=\"VirtualKeyKegDef.inl\">\n      <Filter>SOA Files\\Ext\\Input</Filter>\n    </None>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "SoA/SOA.vcxproj.yml",
    "content": "Project:\n  DefaultTargets: Build\n  Import:\n  - Project: $(VCTargetsPath)\\Microsoft.Cpp.Default.props\n  - Project: $(VCTargetsPath)\\Microsoft.Cpp.props\n  - Project: $(VCTargetsPath)\\Microsoft.Cpp.targets\n  ImportGroup:\n  - Label: ExtensionSettings\n  - Condition: '''$(Configuration)|$(Platform)''==''Debug|Win32'''\n    Import:\n      Condition: exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\n      Label: LocalAppDataPlatform\n      Project: $(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\n    Label: PropertySheets\n  - Condition: '''$(Configuration)|$(Platform)''==''Release|Win32'''\n    Import:\n      Condition: exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\n      Label: LocalAppDataPlatform\n      Project: $(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\n    Label: PropertySheets\n  - Label: ExtensionTargets\n  ItemDefinitionGroup:\n  - ClCompile:\n      AdditionalIncludeDirectories: $(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)\n      ForcedIncludeFiles: null\n      ForcedUsingFiles: null\n      Optimization: Disabled\n      PrecompiledHeader: Use\n      PreprocessorDefinitions: WINDOWS;DEBUG;%(PreprocessorDefinitions)\n      WarningLevel: Level3\n    Condition: '''$(Configuration)|$(Platform)''==''Debug|Win32'''\n    Link:\n      AdditionalDependencies: opengl32.lib;glew32.lib;SDL2.lib;SDL2main.lib;SDL2_ttf.lib;awesomium.lib;fmod_vc.lib;zdll.lib;%(AdditionalDependencies)\n      AdditionalLibraryDirectories: $(SolutionDir)deps\\lib;%(AdditionalLibraryDirectories)\n      GenerateDebugInformation: 'true'\n      LargeAddressAware: 'true'\n      SubSystem: Console\n  - ClCompile:\n      AdditionalIncludeDirectories: $(SolutionDir)deps\\include;%(AdditionalIncludeDirectories)\n      FavorSizeOrSpeed: Speed\n      ForcedIncludeFiles: null\n      ForcedUsingFiles: null\n      FunctionLevelLinking: 'true'\n      InlineFunctionExpansion: OnlyExplicitInline\n      IntrinsicFunctions: 'true'\n      MultiProcessorCompilation: 'true'\n      Optimization: MaxSpeed\n      PrecompiledHeader: Use\n      PreprocessorDefinitions: WINDOWS;NDEBUG;%(PreprocessorDefinitions)\n      WarningLevel: Level3\n    Condition: '''$(Configuration)|$(Platform)''==''Release|Win32'''\n    Link:\n      AdditionalDependencies: opengl32.lib;glew32.lib;SDL2.lib;SDL2main.lib;SDL2_ttf.lib;awesomium.lib;fmod_vc.lib;zdll.lib;%(AdditionalDependencies)\n      AdditionalLibraryDirectories: $(SolutionDir)deps\\lib;%(AdditionalLibraryDirectories)\n      EnableCOMDATFolding: 'true'\n      GenerateDebugInformation: 'true'\n      LargeAddressAware: 'true'\n      OptimizeReferences: 'true'\n      SubSystem: Console\n  ItemGroup:\n  - Label: ProjectConfigurations\n    ProjectConfiguration:\n    - Configuration: Debug\n      Include: Debug|Win32\n      Platform: Win32\n    - Configuration: Release\n      Include: Release|Win32\n      Platform: Win32\n  - ClInclude:\n    - Include: src\\ChunkUpdater.h\n    - Include: src\\LoadBar.h\n    - Include: src\\LoadScreen.h\n    - Include: src\\CAEngine.h\n    - Include: src\\ChunkGenerator.h\n    - Include: src\\ChunkMesher.h\n    - Include: src\\ChunkRenderer.h\n    - Include: src\\ChunkWorker.h\n    - Include: src\\DebugRenderer.h\n    - Include: src\\DepthState.h\n    - Include: src\\FragFile.h\n    - Include: src\\IGameScreen.h\n    - Include: src\\GLEnums.h\n    - Include: src\\GLProgram.h\n    - Include: src\\GLTexture.h\n    - Include: src\\GraphicsDevice.h\n    - Include: src\\IOManager.h\n    - Include: src\\Item.h\n    - Include: src\\MainGame.h\n    - Include: src\\MaterialAtlas.h\n    - Include: src\\MaterialData.h\n    - Include: src\\MaterialStack.h\n    - Include: src\\Particle.h\n    - Include: src\\ParticleBatch.h\n    - Include: src\\ParticleEmitter.h\n    - Include: src\\ParticleEngine.h\n    - Include: src\\ParticleMesh.h\n    - Include: src\\PtrRecycler.h\n    - Include: src\\RasterizerState.h\n    - Include: src\\SamplerState.h\n    - Include: src\\ScreenList.h\n    - Include: src\\SpriteBatch.h\n    - Include: src\\SpriteFont.h\n    - Include: src\\stdafx.h\n    - Include: src\\App.h\n    - Include: src\\TextureAtlasManager.h\n    - Include: src\\VoxelEditor.h\n    - Include: src\\Thread.h\n    - Include: src\\WSO.h\n    - Include: src\\WSOAtlas.h\n    - Include: src\\WSOScanner.h\n    - Include: src\\WSOData.h\n    - Include: src\\Inputs.h\n    - Include: src\\InputManager.h\n    - Include: src\\Actor.h\n    - Include: src\\atomicops.h\n    - Include: src\\BlockData.h\n    - Include: src\\Camera.h\n    - Include: src\\Chunk.h\n    - Include: src\\ChunkManager.h\n    - Include: src\\Collision.h\n    - Include: src\\Constants.h\n    - Include: src\\Errors.h\n    - Include: src\\FileSystem.h\n    - Include: src\\FrameBuffer.h\n    - Include: src\\Frustum.h\n    - Include: src\\GameControls.h\n    - Include: src\\GameManager.h\n    - Include: src\\GameMenu.h\n    - Include: src\\global.h\n    - Include: src\\ImageLoading.h\n    - Include: src\\LoadTask.h\n    - Include: src\\PhysicsBlocks.h\n    - Include: src\\PhysicsEngine.h\n    - Include: src\\Random.h\n    - Include: src\\RenderTask.h\n    - Include: src\\RenderUtils.h\n    - Include: src\\TaskQueueManager.h\n    - Include: src\\TerrainPatch.h\n    - Include: src\\lodepng.h\n    - Include: src\\ObjectLoader.h\n    - Include: src\\OpenglManager.h\n    - Include: src\\OpenGLStructs.h\n    - Include: src\\Options.h\n    - Include: src\\Particles.h\n    - Include: src\\Planet.h\n    - Include: src\\Player.h\n    - Include: src\\readerwriterqueue.h\n    - Include: src\\Rendering.h\n    - Include: src\\shader.h\n    - Include: src\\SimplexNoise.h\n    - Include: src\\Sound.h\n    - Include: src\\TerrainGenerator.h\n    - Include: src\\Texture2d.h\n    - Include: src\\ThreadPool.h\n    - Include: src\\AwesomiumUI.h\n    - Include: src\\FloraGenerator.h\n    - Include: src\\types.h\n    - Include: src\\utils.h\n    - Include: src\\VoxelRay.h\n    - Include: src\\VRayHelper.h\n    - Include: src\\WorldEditor.h\n    - Include: src\\WorldIO.h\n    - Include: src\\WorldStructs.h\n    - Include: src\\VoxelWorld.h\n    - Include: src\\VoxDefs.h\n    - Include: src\\EditorVariables.h\n    - Include: src\\ZipFile.h\n  - ClCompile:\n    - Include: ..\\deps\\include\\JSON\\json_spirit_reader.cpp\n      PrecompiledHeader:\n      - Condition: '''$(Configuration)|$(Platform)''==''Debug|Win32'''\n        text: NotUsing\n      - Condition: '''$(Configuration)|$(Platform)''==''Release|Win32'''\n        text: NotUsing\n    - Include: src\\ChunkUpdater.cpp\n    - Include: src\\LoadBar.cpp\n    - Include: src\\LoadScreen.cpp\n    - Include: src\\CAEngine.cpp\n    - Include: src\\ChunkGenerator.cpp\n    - Include: src\\ChunkRenderer.cpp\n    - Include: src\\ChunkWorker.cpp\n    - Include: src\\DebugRenderer.cpp\n    - Include: src\\DepthState.cpp\n    - Include: src\\FragFile.cpp\n    - Include: src\\GLProgram.cpp\n    - Include: src\\GLTexture.cpp\n    - Include: src\\GraphicsDevice.cpp\n    - Include: src\\InputManager.cpp\n    - Include: src\\Actor.cpp\n    - Include: src\\BlockData.cpp\n    - Include: src\\Camera.cpp\n    - Include: src\\Chunk.cpp\n    - Include: src\\Inputs.cpp\n    - Include: src\\IOManager.cpp\n    - Include: src\\MainGame.cpp\n    - Include: src\\Particle.cpp\n    - Include: src\\ParticleBatch.cpp\n    - Include: src\\ParticleEmitter.cpp\n    - Include: src\\ParticleEngine.cpp\n    - Include: src\\PhysicsBlocks.cpp\n    - Include: src\\PhysicsEngine.cpp\n    - Include: src\\Random.cpp\n    - Include: src\\FloraGenerator.cpp\n    - Include: src\\RasterizerState.cpp\n    - Include: src\\RenderUtils.cpp\n    - Include: src\\SamplerState.cpp\n    - Include: src\\ScreenList.cpp\n    - Include: src\\SpriteBatch.cpp\n    - Include: src\\SpriteFont.cpp\n    - Include: src\\stdafx.cpp\n      PrecompiledHeader:\n      - Condition: '''$(Configuration)|$(Platform)''==''Debug|Win32'''\n        text: Create\n      - Condition: '''$(Configuration)|$(Platform)''==''Release|Win32'''\n        text: Create\n    - Include: src\\App.cpp\n    - Include: src\\TextureAtlasManager.cpp\n    - Include: src\\VoxelEditor.cpp\n    - Include: src\\VoxelRay.cpp\n    - Include: src\\VRayHelper.cpp\n    - Include: src\\WorldIO.cpp\n    - Include: src\\ChunkManager.cpp\n    - Include: src\\ChunkMesher.cpp\n    - Include: src\\CloseTerrainPatch.cpp\n    - Include: src\\Collision.cpp\n    - Include: src\\Errors.cpp\n    - Include: src\\FileSystem.cpp\n    - Include: src\\FrameBuffer.cpp\n    - Include: src\\Frustum.cpp\n    - Include: src\\GameControls.cpp\n    - Include: src\\GameManager.cpp\n    - Include: src\\GameMenu.cpp\n    - Include: src\\global.cpp\n    - Include: src\\ImageLoading.cpp\n    - Include: src\\TerrainPatch.cpp\n    - Include: src\\lodepng.cpp\n    - Include: src\\main.cpp\n    - Include: src\\ObjectLoader.cpp\n    - Include: src\\OpenglManager.cpp\n    - Include: src\\Options.cpp\n    - Include: src\\Planet.cpp\n    - Include: src\\Player.cpp\n    - Include: src\\Rendering.cpp\n    - Include: src\\shader.cpp\n    - Include: src\\SimplexNoise.cpp\n    - Include: src\\Sound.cpp\n    - Include: src\\TerrainGenerator.cpp\n    - Include: src\\Texture2d.cpp\n    - Include: src\\ThreadPool.cpp\n    - Include: src\\AwesomiumUI.cpp\n    - Include: src\\WorldEditor.cpp\n    - Include: src\\WorldStructs.cpp\n    - Include: src\\VoxelWorld.cpp\n    - Include: src\\WSO.cpp\n    - Include: src\\WSOAtlas.cpp\n    - Include: src\\WSOScanner.cpp\n    - Include: src\\ZipFile.cpp\n  - ResourceCompile:\n      Include: Resources\\resources.rc\n  - Image:\n      Include: Resources\\SOA.ico\n  - Text:\n    - Include: docs\\FileSpecs\\WSO.txt\n    - Include: TODO.txt\n  - None:\n      Include: src\\Chunk.inl\n  PropertyGroup:\n  - Label: Globals\n    ProjectGuid: '{588491F3-69BA-40E7-8CE8-2382A64D86E3}'\n    RootNamespace: SOA\n  - CharacterSet: MultiByte\n    Condition: '''$(Configuration)|$(Platform)''==''Debug|Win32'''\n    ConfigurationType: Application\n    Label: Configuration\n    PlatformToolset: v120\n    UseDebugLibraries: 'true'\n  - CharacterSet: MultiByte\n    Condition: '''$(Configuration)|$(Platform)''==''Release|Win32'''\n    ConfigurationType: Application\n    Label: Configuration\n    PlatformToolset: v120_xp\n    UseDebugLibraries: 'false'\n    WholeProgramOptimization: 'true'\n  - Label: UserMacros\n  - Condition: '''$(Configuration)|$(Platform)''==''Release|Win32'''\n    IncludePath: $(SolutionDir)deps\\Seed_Of_Andromeda_Deps\\include;$(IncludePath)\n    LibraryPath: $(SolutionDir)deps\\Seed_Of_Andromeda_Deps\\lib;$(LibraryPath)\n  - Condition: '''$(Configuration)|$(Platform)''==''Debug|Win32'''\n    IncludePath: $(SolutionDir)deps\\Seed_Of_Andromeda_Deps\\include;$(IncludePath)\n    IntDir: $(Configuration)\n    LibraryPath: $(SolutionDir)deps\\Seed_Of_Andromeda_Deps\\lib;$(LibraryPath)\n  ToolsVersion: '12.0'\n  xmlns: http://schemas.microsoft.com/developer/msbuild/2003\n"
  },
  {
    "path": "SoA/ShaderAssetLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ShaderAssetLoader.h\"\n\n#include <tuple>\n\n#include <Vorb/io/IOManager.h>\n#include <Vorb/io/Keg.h>\n\n// TODO(Ben): Use shader loader\nnamespace {\n    typedef std::pair<nString, VGAttribute> AttributeBinding;\n    KEG_TYPE_DECL(Anon_AttributeBinding);\n    KEG_TYPE_DEF(Anon_AttributeBinding, AttributeBinding, kt) {\n        using namespace keg;\n        kt.addValue(\"Name\", Value::value(&AttributeBinding::first));\n        kt.addValue(\"Location\", Value::value(&AttributeBinding::second));\n    }\n\n    struct ShaderAssetInformation {\n    public:\n        nString vertexFile;\n        nString fragmentFile;\n        Array<AttributeBinding> binds;\n        Array<AttributeBinding> frags;\n        Array<nString> defines;\n    };\n    KEG_TYPE_DECL(Anon_ShaderAssetInformation);\n    KEG_TYPE_DEF(Anon_ShaderAssetInformation, ShaderAssetInformation, kt) {\n        using namespace keg;\n        kt.addValue(\"Vertex\", Value::value(&ShaderAssetInformation::vertexFile));\n        kt.addValue(\"Fragment\", Value::value(&ShaderAssetInformation::fragmentFile));\n        kt.addValue(\"Attributes\", Value::array(offsetof(ShaderAssetInformation, binds), Value::custom(0, \"Anon_AttributeBinding\")));\n        kt.addValue(\"Fragments\", Value::array(offsetof(ShaderAssetInformation, frags), Value::custom(0, \"Anon_AttributeBinding\")));\n        kt.addValue(\"Defines\", Value::array(offsetof(ShaderAssetInformation, defines), BasicType::STRING));\n    }\n\n    void initProgram(Sender, void* ptr) {\n        auto& program = ((ShaderAsset*)ptr)->program;\n        program.init();\n    }\n    void finishProgram(Sender, void* ptr) {\n        auto& program = ((ShaderAsset*)ptr)->program;\n        program.link();\n        program.initAttributes();\n        program.initUniforms();\n    }\n\n    typedef std::tuple<ShaderAsset*, vg::ShaderType, const cString, Array<nString>&> CompileArgs;\n    void compileShader(Sender, void* ptr) {\n        auto& args = *(CompileArgs*)ptr;\n\n        vg::ShaderSource source;\n        source.stage = std::get<1>(args);\n\n        // Add macros\n        Array<nString>& defines = std::get<3>(args);\n        char buf[1024];\n        char* dest = buf;\n        for (size_t i = 0; i < defines.size(); i++) {\n            source.sources.push_back(dest);\n            dest += sprintf(dest, \"#define %s\\n\", defines[i].c_str());\n        }\n\n        // Add shader code\n        source.sources.push_back(std::get<2>(args));\n\n        // Compile\n        std::get<0>(args)->program.addShader(source);\n    }\n\n    typedef std::tuple<ShaderAsset*, ShaderAssetInformation*> BindArgs;\n    void bindAttributes(Sender, void* ptr) {\n        auto& args = *(BindArgs*)ptr;\n        auto& binds = std::get<1>(args)->binds;\n        vg::GLProgram& program = std::get<0>(args)->program;\n        for (size_t i = 0; i < binds.size(); i++) {\n            program.setAttribute(binds[i].first, binds[i].second);\n        }\n    }\n    void bindFragments(Sender, void* ptr) {\n        auto& args = *(BindArgs*)ptr;\n        auto& binds = std::get<1>(args)->binds;\n        vg::GLProgram& program = std::get<0>(args)->program;\n        for (size_t i = 0; i < binds.size(); i++) {\n            program.bindFragDataLocation(binds[i].second, binds[i].first.c_str());\n        }\n    }\n}\n\nvoid vcore::AssetBuilder<ShaderAsset>::create(const vpath& p, OUT ShaderAsset* asset, vcore::RPCManager& rpc) {\n    GLRPC so(asset);\n    vio::IOManager iom;\n\n    // Read the YAML information\n    ShaderAssetInformation info{};\n    const cString str = iom.readFileToString(p);\n    keg::parse(&info, str, \"Anon_ShaderAssetInformation\");\n    delete[] str;\n\n    // Set the root directory to the YAML info file\n    vpath root = p;\n    root--;\n    iom.setSearchDirectory(root);\n\n    // Initialize the program\n    so.set([](Sender s, void* d) { initProgram(s, d); });\n    rpc.invoke(&so);\n\n    auto func1=[=](Sender, const nString& msg) {\n        printf(\"PROG COMP ERROR:\\n%s\\n\", msg.c_str());\n    };\n    auto d1 = makeDelegate(&func1);\n\n    auto func2=[=](Sender, const nString& msg) {\n        printf(\"PROG LINK ERROR:\\n%s\\n\", msg.c_str());\n    };\n    auto d2 = makeDelegate(&func2);\n\n    asset->program.onShaderCompilationError += d1;\n    asset->program.onProgramLinkError += d2;\n\n    { // Read vertex file\n        str = iom.readFileToString(info.vertexFile);\n        CompileArgs args(asset, vg::ShaderType::VERTEX_SHADER, str, info.defines);\n        so.data.userData = &args;\n        so.set([](Sender s, void* d) { compileShader(s, d); });\n        rpc.invoke(&so);\n        delete[] str;\n    }\n\n    { // Read fragment file\n        str = iom.readFileToString(info.fragmentFile);\n        CompileArgs args(asset, vg::ShaderType::FRAGMENT_SHADER, str, info.defines);\n        so.data.userData = &args;\n        so.set([](Sender s, void* d) { compileShader(s, d); });\n        rpc.invoke(&so);\n        delete[] str;\n    }\n\n    { // Bind all attribute locations\n        BindArgs args(asset, &info);\n        so.data.userData = &args;\n        so.set([](Sender s, void* d) { bindAttributes(s, d); });\n        rpc.invoke(&so);\n    }\n\n    if (info.frags.size() > 0) {\n        // Bind all fragment locations\n        BindArgs args(asset, &info);\n        so.data.userData = &args;\n        so.set([](Sender s, void* d) { bindFragments(s, d); });\n        rpc.invoke(&so);\n    }\n\n    // Link the program\n    so.data.userData = asset;\n    so.set([](Sender s, void* d) { finishProgram(s, d); });\n    rpc.invoke(&so);\n\n    asset->program.onShaderCompilationError -= d1;\n    asset->program.onProgramLinkError -= d2;\n}\nvoid vcore::AssetBuilder<ShaderAsset>::destroy(ShaderAsset* asset) {\n    asset->program.dispose();\n}\n"
  },
  {
    "path": "SoA/ShaderAssetLoader.h",
    "content": "///\n/// ShaderAssetLoader.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 4 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Handles loading shader assets\n///\n\n#pragma once\n\n#ifndef ShaderAssetLoader_h__\n#define ShaderAssetLoader_h__\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/AssetLoader.h>\n\nclass ShaderAsset : public vcore::Asset {\npublic:\n    vg::GLProgram program;\n};\n\ntemplate<>\nstruct vcore::AssetBuilder<ShaderAsset> {\npublic:\n    void create(const vpath& p, OUT ShaderAsset* asset, vcore::RPCManager& rpc);\n    void destroy(ShaderAsset* asset);\n};\n\nCONTEXTUAL_ASSET_LOADER(ShaderAssetLoader, ShaderAsset);\n\n#endif // ShaderAssetLoader_h__\n"
  },
  {
    "path": "SoA/ShaderLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ShaderLoader.h\"\n\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/ShaderManager.h>\n\nnamespace {\n    void printShaderError(Sender s VORB_MAYBE_UNUSED, const nString& n) {\n        puts(\"Shader Error: \");\n        puts(n.c_str());\n    }\n    void printLinkError(Sender s VORB_MAYBE_UNUSED, const nString& n) {\n        puts(\"Link Error: \");\n        puts(n.c_str());\n    }\n    void printFileIOError(Sender s VORB_MAYBE_UNUSED, const nString& n) {\n        puts(\"FIle IO Error: \");\n        puts(n.c_str());\n    }\n}\n\nCALLER_DELETE vg::GLProgram ShaderLoader::createProgramFromFile(const vio::Path& vertPath, const vio::Path& fragPath,\n                                                                vio::IOManager* iom /*= nullptr*/, const cString defines /*= nullptr*/) {\n    vg::ShaderManager::onFileIOFailure += makeDelegate(printFileIOError);\n    vg::ShaderManager::onShaderCompilationError += makeDelegate(printShaderError);\n    vg::ShaderManager::onProgramLinkError += makeDelegate(printLinkError);\n\n    vg::GLProgram program;\n    while (true) {\n        program = vg::ShaderManager::createProgramFromFile(vertPath, fragPath, iom, defines);\n        if (program.isLinked()) break;\n        program.dispose();\n        printf(\"Enter any key to try recompiling with Vertex Shader: %s and Fragment Shader %s\\nEnter Z to abort.\\n\", vertPath.getCString(), fragPath.getCString());\n        char tmp;\n        std::cin >> tmp;\n        if (tmp == 'Z' || tmp == 'z') break;\n    }\n\n    vg::ShaderManager::onFileIOFailure -= makeDelegate(printFileIOError);\n    vg::ShaderManager::onShaderCompilationError -= makeDelegate(printShaderError);\n    vg::ShaderManager::onProgramLinkError -= makeDelegate(printLinkError);\n    return program;\n}\n\nCALLER_DELETE vg::GLProgram ShaderLoader::createProgram(const cString displayName, const cString vertSrc, const cString fragSrc, vio::IOManager* iom /*= nullptr*/, const cString defines /*= nullptr*/) {\n    vg::ShaderManager::onFileIOFailure += makeDelegate(printFileIOError);\n    vg::ShaderManager::onShaderCompilationError += makeDelegate(printShaderError);\n    vg::ShaderManager::onProgramLinkError += makeDelegate(printLinkError);\n\n    vg::GLProgram program;\n    while (true) {\n        program = vg::ShaderManager::createProgram(vertSrc, fragSrc, iom, iom, defines);\n        if (program.isLinked()) break;\n        program.dispose();\n        printf(\"Enter any key to try recompiling with %s shader.\\nEnter Z to abort.\\n\", displayName);\n        char tmp;\n        std::cin >> tmp;\n        if (tmp == 'Z' || tmp == 'z') break;\n    }\n\n    vg::ShaderManager::onFileIOFailure -= makeDelegate(printFileIOError);\n    vg::ShaderManager::onShaderCompilationError -= makeDelegate(printShaderError);\n    vg::ShaderManager::onProgramLinkError -= makeDelegate(printLinkError);\n    return program;\n}\n"
  },
  {
    "path": "SoA/ShaderLoader.h",
    "content": "///\n/// ShaderLoader.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 31 Mar 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Handles easy loading and error checking of shaders for SoA\n///\n\n#pragma once\n\n#ifndef ShaderLoader_h__\n#define ShaderLoader_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/io/Path.h>\n#include <Vorb/graphics/GLProgram.h>\n\nDECL_VIO(class IOManager);\n\n#pragma once\nclass ShaderLoader {\npublic:\n    /// Creates a program using code loaded from files, and does error checking\n    /// Does not register with global cache\n    static CALLER_DELETE vg::GLProgram createProgramFromFile(const vio::Path& vertPath, const vio::Path& fragPath,\n                                                             vio::IOManager* iom = nullptr, const cString defines = nullptr);\n\n    /// Creates a program using passed code, and does error checking\n    /// Does not register with global cache\n    static CALLER_DELETE vg::GLProgram createProgram(const cString displayName, const cString vertSrc, const cString fragSrc,\n                                                     vio::IOManager* iom = nullptr, const cString defines = nullptr);\n};\n\n#endif // ShaderLoader_h__\n\n"
  },
  {
    "path": "SoA/SkyboxRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SkyboxRenderStage.h\"\n\n#include <GL/glew.h>\n#include <Vorb/graphics/DepthState.h>\n#include <Vorb/io/IOManager.h>\n\n#include \"Camera.h\"\n#include \"Errors.h\"\n#include \"LoadContext.h\"\n#include \"ModPathResolver.h\"\n#include \"ShaderLoader.h\"\n#include \"SkyboxRenderer.h\"\n#include \"SoAState.h\"\n\n#include <glm/gtc/matrix_transform.hpp>\n\nconst ui32 TASK_WORK = 4;\nconst ui32 TOTAL_TASKS = 8;\nconst ui32 TOTAL_WORK = TOTAL_TASKS * TASK_WORK;\n\nvoid SkyboxRenderStage::init(vui::GameWindow* window, StaticLoadContext& context) {\n    IRenderStage::init(window, context);\n    context.addAnticipatedWork(TOTAL_WORK, TOTAL_TASKS);\n}\n\nvoid SkyboxRenderStage::hook(SoaState* state) {\n    m_textureResolver = &state->clientState.texturePathResolver;\n}\n\nvoid SkyboxRenderStage::load(StaticLoadContext& context) {\n    // Create texture array\n    context.addTask([&](Sender, void*) {\n        glGenTextures(1, &m_skyboxTextureArray);\n        m_skyboxRenderer.initGL();\n        context.addWorkCompleted(TASK_WORK);\n        checkGlError(\"SkyboxRenderStage inittt\");\n    }, false);\n\n    // Front (also allocates storage)\n    context.addTask([&](Sender, void*) {\n        vio::Path path;\n        m_textureResolver->resolvePath(\"Sky/Skybox/front.png\", path);\n        vg::ScopedBitmapResource frontRes(vg::ImageIO().load(path));\n        m_resolution = frontRes.width;\n        if (frontRes.height != m_resolution) {\n            pError(\"Skybox textures must have equal width and height!\");\n        }\n        if (frontRes.data == nullptr) pError(\"Failed to load Sky/Skybox/front.png\");\n        glBindTexture(GL_TEXTURE_2D_ARRAY, m_skyboxTextureArray);\n        // Calculate max mipmap level\n        int maxMipLevel = 0;\n        int width = m_resolution;\n        while (width > 1) {\n            width >>= 1;\n            maxMipLevel++;\n        }\n        // Set up all the storage\n        width = m_resolution;\n        for (i32 i = 0; i < maxMipLevel; i++) {\n            glTexImage3D(GL_TEXTURE_2D_ARRAY, i, GL_RGBA8, width, width, 6, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);\n            width >>= 1;\n            if (width < 1) width = 1;\n        }\n        // Set mipmap parameters\n        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LOD, maxMipLevel);\n        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, maxMipLevel);\n        // Upload data\n        glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, frontRes.width, frontRes.height, 1, GL_RGBA, GL_UNSIGNED_BYTE, frontRes.data);\n        context.addWorkCompleted(TASK_WORK);\n        checkGlError(\"SkyboxRenderStage waaaa\");\n    }, false);\n    // Right\n    context.addTask([&](Sender, void*) {\n        loadTexture(\"Sky/Skybox/right.png\", 1);\n        context.addWorkCompleted(TASK_WORK);\n    }, false);\n    // Top\n    context.addTask([&](Sender, void*) {\n        loadTexture(\"Sky/Skybox/top.png\", 2);\n        context.addWorkCompleted(TASK_WORK);\n    }, false);\n    // Left\n    context.addTask([&](Sender, void*) {\n        loadTexture(\"Sky/Skybox/left.png\", 3);\n        context.addWorkCompleted(TASK_WORK);\n    }, false);\n    // Bottom\n    context.addTask([&](Sender, void*) {\n        loadTexture(\"Sky/Skybox/bottom.png\", 4);\n        context.addWorkCompleted(TASK_WORK);\n    }, false);\n    // Back\n    context.addTask([&](Sender, void*) {\n        loadTexture(\"Sky/Skybox/back.png\", 5);\n        context.addWorkCompleted(TASK_WORK);\n    }, false);\n\n    // Tex parameters and mipmaps\n    context.addTask([&](Sender, void*) {\n        glBindTexture(GL_TEXTURE_2D_ARRAY, m_skyboxTextureArray);\n\n        // Set up tex parameters\n        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);\n        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);\n        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);\n        glGenerateMipmap(GL_TEXTURE_2D_ARRAY);\n\n        // Unbind\n        glBindTexture(GL_TEXTURE_2D_ARRAY, 0);\n\n        // Check if we had any errors\n        checkGlError(\"SkyboxRenderStage mipmaps\");\n        context.addWorkCompleted(TASK_WORK);\n    }, false);\n}\n\nvoid SkyboxRenderStage::render(const Camera* camera) {\n\n    // Check if FOV or Aspect Ratio changed\n    if (m_fieldOfView != camera->getFieldOfView() ||\n        m_aspectRatio != camera->getAspectRatio()) {\n        updateProjectionMatrix(camera);\n    }\n    // Draw using custom proj and camera view\n    drawSpace(m_projectionMatrix * camera->getViewMatrix());\n}\n\n\nvoid SkyboxRenderStage::drawSpace(const f32m4 &VP) {\n    vg::DepthState::NONE.set();\n    m_skyboxRenderer.drawSkybox(VP, m_skyboxTextureArray);\n    vg::DepthState::FULL.set();\n}\n\nvoid SkyboxRenderStage::updateProjectionMatrix(const Camera* camera) {\n    // Set the camera clipping plane for rendering the skybox and set the projection matrix\n    // The clipping dimensions don't matter so long as the skybox fits inside them\n    #define SKYBOX_ZNEAR 0.01f\n    #define SKYBOX_ZFAR 300.0f\n\n    m_fieldOfView = camera->getFieldOfView();\n    m_aspectRatio = camera->getAspectRatio();\n\n    // Set up projection matrix\n    m_projectionMatrix = glm::perspective(m_fieldOfView, m_aspectRatio, SKYBOX_ZNEAR, SKYBOX_ZFAR);\n}\n\nvoid SkyboxRenderStage::loadTexture(const char* relPath, int index) {\n    vio::Path path;\n    m_textureResolver->resolvePath(relPath, path);\n    vg::ScopedBitmapResource res(vg::ImageIO().load(path));\n    if (res.height != m_resolution || res.width != m_resolution) {\n        pError(\"Skybox textures must all have equal width and height!\");\n    }\n    if (res.data == nullptr) pError(\"Failed to load \" + nString(relPath));\n    glBindTexture(GL_TEXTURE_2D_ARRAY, m_skyboxTextureArray);\n    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, index, res.width, res.height, 1, GL_RGBA, GL_UNSIGNED_BYTE, res.data);  \n    checkGlError(\"SkyboxRenderStage::load() \" + nString(relPath));\n}"
  },
  {
    "path": "SoA/SkyboxRenderStage.h",
    "content": "/// \n///  SkyboxRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file provides the implementation for the skybox render stage\n///\n\n#pragma once\n\n#ifndef SkyboxRenderStage_h__\n#define SkyboxRenderStage_h__\n\n#include \"SkyboxRenderer.h\"\n#include \"IRenderStage.h\"\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/AssetLoader.h>\n\nclass Camera;\nclass ModPathResolver;\n\nclass SkyboxRenderStage : public IRenderStage\n{\npublic:\n    void init(vui::GameWindow* window, StaticLoadContext& context) override;\n\n    void hook(SoaState* state);\n\n    void load(StaticLoadContext& context) override;\n\n    // Draws the render stage\n    virtual void render(const Camera* camera) override;\nprivate:\n    void drawSpace(const f32m4 &VP);\n    // Update projection matrix\n    void updateProjectionMatrix(const Camera* camera);\n    void loadTexture(const char* relPath, int index);\n\n    SkyboxRenderer m_skyboxRenderer; ///< Renders the skybox\n//    vg::GLProgram* m_program = nullptr; ///< Program used for rendering\n\n    f32m4 m_projectionMatrix; ///< Projection matrix for the skybox\n    float m_fieldOfView; ///< Current field of view for the camera\n    float m_aspectRatio; ///< Current aspect ratio for the camera\n\n    VGTexture m_skyboxTextureArray = 0; ///< Texture array for skybox\n    const ModPathResolver* m_textureResolver = nullptr;\n    vcore::GLRPC m_rpc;\n    ui32 m_resolution;\n\n    // For parallel loading\n\n};\n\n#endif // SkyboxRenderStage_h__\n"
  },
  {
    "path": "SoA/SkyboxRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SkyboxRenderer.h\"\n#include \"LoadContext.h\"\n\n#include <Vorb/graphics/GLEnums.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/ShaderManager.h>\n\n#include \"ShaderLoader.h\"\n\n// Skybox Cube //\n//    v6----- v5\n//   /|      /|\n//  v1------v0|\n//  | |     | |\n//  | |v7---|-|v4\n//  |/      |/\n//  v2------v3\n\n#define INDICES_PER_QUAD 6\n#define VERTS_PER_QUAD 4\n#define SKYBOX_FACES 6\n\nconst float skyboxSize = 10.0f;\nconst float skyboxVertices[72] = {\n    -skyboxSize, skyboxSize, skyboxSize, -skyboxSize, -skyboxSize, skyboxSize, skyboxSize, -skyboxSize, skyboxSize, skyboxSize, skyboxSize, skyboxSize,  // v1-v2-v3-v0 (front)\n    skyboxSize, skyboxSize, skyboxSize, skyboxSize, -skyboxSize, skyboxSize, skyboxSize, -skyboxSize, -skyboxSize, skyboxSize, skyboxSize, -skyboxSize,     // v0-v3-v4-v5 (right)\n    -skyboxSize, skyboxSize, -skyboxSize, -skyboxSize, skyboxSize, skyboxSize, skyboxSize, skyboxSize, skyboxSize, skyboxSize, skyboxSize, -skyboxSize,    // v6-v1-v0-v5 (top)\n    -skyboxSize, skyboxSize, -skyboxSize, -skyboxSize, -skyboxSize, -skyboxSize, -skyboxSize, -skyboxSize, skyboxSize, -skyboxSize, skyboxSize, skyboxSize,   // v6-v7-v2-v1 (left)\n    -skyboxSize, -skyboxSize, -skyboxSize, skyboxSize, -skyboxSize, -skyboxSize, skyboxSize, -skyboxSize, skyboxSize, -skyboxSize, -skyboxSize, skyboxSize,    // v7-v4-v3-v2 (bottom)\n    skyboxSize, skyboxSize, -skyboxSize, skyboxSize, -skyboxSize, -skyboxSize, -skyboxSize, -skyboxSize, -skyboxSize, -skyboxSize, skyboxSize, -skyboxSize };     // v5-v4-v7-v6 (back)\n\n// These are the X,Y components. The Z component is determined by integer division\nconst float skyboxUVs[48] = { 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,  // v1-v2-v3-v0 (front)\n1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, // v0-v3-v4-v5 (right)\n1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,// v6-v1-v0-v5 (top)\n1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,// v6-v7-v2-v1 (left)\n1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0,  // v7-v4-v3-v2 (bottom)\n1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; // v5-v4-v7-v6 (back)\n\nnamespace {\n    const cString VERT_SRC = R\"(\nuniform mat4 unWVP;\nin vec4 vPosition;\nin vec3 vUVW;\nout vec3 fUVW;\nvoid main() {\n  fUVW = vUVW;\n  gl_Position = unWVP * vPosition;\n}\n)\";\n    const cString FRAG_SRC = R\"(\nuniform sampler2DArray unTex;\nin vec3 fUVW;\nout vec4 pColor;\nvoid main() {\n  pColor = texture(unTex, vec3(fUVW.xyz));\n  pColor.a = 1.0;\n})\";\n}\n\nSkyboxRenderer::SkyboxRenderer() {\n    // Empty\n}\n\nSkyboxRenderer::~SkyboxRenderer() {\n    destroy();\n}\n\nvoid SkyboxRenderer::initGL() {\n    initShader();\n    initBuffers();\n}\n\nvoid SkyboxRenderer::drawSkybox(const f32m4& VP, VGTexture textureArray) {\n\n    // Bind shader\n    m_program.use();\n\n    // Bind our texture in Texture Unit 0\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D_ARRAY, textureArray);\n    // Upload VP matrix\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, GL_FALSE, &VP[0][0]);\n    \n    // Create the buffer objects if they aren't initialized\n    if (m_vbo == 0) {\n        initBuffers();\n    }\n\n    glBindVertexArray(m_vao);\n    glDrawElements(GL_TRIANGLES, INDICES_PER_QUAD * 6, GL_UNSIGNED_SHORT, (void*)0); //offset\n    glBindVertexArray(0);\n\n    // Unbind shader\n    m_program.unuse();  \n}\n\nvoid SkyboxRenderer::destroy() {\n    if (m_vao) {\n        glDeleteVertexArrays(1, &m_vao);\n        m_vao = 0;\n    }\n    if (m_vbo) {\n        vg::GpuMemory::freeBuffer(m_vbo);\n        m_vbo = 0;\n    }\n    if (m_ibo) {\n        vg::GpuMemory::freeBuffer(m_ibo);\n        m_ibo = 0;\n    }\n    if (m_program.isCreated()) m_program.dispose();\n}\n\nvoid SkyboxRenderer::initShader() {\n    m_program = ShaderLoader::createProgram(\"Skybox\", VERT_SRC, FRAG_SRC);\n\n    // Constant uniforms\n    m_program.use();\n    glUniform1i(m_program.getUniform(\"unTex\"), 0);\n    m_program.unuse();\n}\n\nvoid SkyboxRenderer::initBuffers() {\n    // Vertex Array Object\n    glGenVertexArrays(1, &m_vao);\n    glBindVertexArray(m_vao);\n\n    // Vertex Buffer Object\n    vg::GpuMemory::createBuffer(m_vbo);\n    vg::GpuMemory::bindBuffer(m_vbo, vg::BufferTarget::ARRAY_BUFFER);\n\n    SkyboxVertex verts[VERTS_PER_QUAD * SKYBOX_FACES];\n    for (int i = 0; i < VERTS_PER_QUAD * SKYBOX_FACES; i++) {\n        verts[i].position = f32v3(skyboxVertices[i * 3],\n                                  skyboxVertices[i * 3 + 1],\n                                  skyboxVertices[i * 3 + 2]);\n        verts[i].texCoords = f32v3(skyboxUVs[i * 2], skyboxUVs[i * 2 + 1], (f32)(i / VERTS_PER_QUAD));\n    }\n\n    vg::GpuMemory::uploadBufferData(m_vbo, vg::BufferTarget::ARRAY_BUFFER, sizeof(verts), verts, vg::BufferUsageHint::STATIC_DRAW);\n\n    vg::GpuMemory::createBuffer(m_ibo);\n    vg::GpuMemory::bindBuffer(m_ibo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n\n    // Index buffer Object\n    ui16 skyboxIndices[INDICES_PER_QUAD * SKYBOX_FACES];\n    // Set up indices\n    i32 ci = 0;\n    for (i32 i = 0; i < INDICES_PER_QUAD * SKYBOX_FACES; i += INDICES_PER_QUAD, ci += VERTS_PER_QUAD) {\n        skyboxIndices[i] = ci;\n        skyboxIndices[i + 1] = ci + 3;\n        skyboxIndices[i + 2] = ci + 2;\n        skyboxIndices[i + 3] = ci + 2;\n        skyboxIndices[i + 4] = ci + 1;\n        skyboxIndices[i + 5] = ci;\n    }\n\n    vg::GpuMemory::uploadBufferData(m_ibo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER, sizeof(skyboxIndices), skyboxIndices, vg::BufferUsageHint::STATIC_DRAW);\n\n    // Set up attribute pointers\n    m_program.enableVertexAttribArrays();\n    glVertexAttribPointer(m_program.getAttribute(\"vPosition\"), 3, GL_FLOAT, GL_FALSE, sizeof(SkyboxVertex), offsetptr(SkyboxVertex, position));\n    glVertexAttribPointer(m_program.getAttribute(\"vUVW\"), 3, GL_FLOAT, GL_FALSE, sizeof(SkyboxVertex), offsetptr(SkyboxVertex, texCoords));\n    glBindVertexArray(0);\n}\n"
  },
  {
    "path": "SoA/SkyboxRenderer.h",
    "content": "/// \n///  SkyboxRenderer.h\n///  Seed of Andromeda\n///\n///  Created by Ben Arnold on 28 Oct 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file provides a class to render a skybox\n///\n\n#pragma once\n\n#ifndef SkyboxRenderer_h__\n#define SkyboxRenderer_h__\n\n#include <Vorb/graphics/GLProgram.h>\n\nclass SkyboxVertex {\npublic:\n    f32v3 position;\n    f32v3 texCoords;\n};\n\nclass LoadContext;\n\nclass SkyboxRenderer\n{\npublic:\n    SkyboxRenderer();\n    ~SkyboxRenderer();\n\n    void initGL();\n\n    /// Draw the skybox\n    void drawSkybox(const f32m4& VP, VGTexture textureArray);\n\n    /// Frees the skybox mesh and shader\n    void destroy();\nprivate:\n\n    /// Initializes the _vbo and _ibo buffers\n    void initShader();\n    void initBuffers();\n\n    ui32 m_vao = 0;\n    ui32 m_vbo = 0;\n    ui32 m_ibo = 0;\n\n    vg::GLProgram m_program;\n};\n\n#endif // SkyboxRenderer_h__\n"
  },
  {
    "path": "SoA/SmartVoxelContainer.hpp",
    "content": "//\n// SmartVoxelContainer.h\n// Vorb Engine\n//\n// Created by Benjamin Arnold on 14 Nov 2014\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef SmartVoxelContainer_h__\n#define SmartVoxelContainer_h__\n\n#include <mutex>\n\n#include \"Constants.h\"\n\n#include <Vorb/FixedSizeArrayRecycler.hpp>\n#include <Vorb/voxel/IntervalTree.h>\n\n#define QUIET_FRAMES_UNTIL_COMPRESS 60\n#define ACCESS_COUNT_UNTIL_DECOMPRESS 5\n\n// TODO(Cristian): We'll see how to fit it into Vorb\nnamespace vorb {\n    namespace voxel {\n\n        static ui32 MAX_COMPRESSIONS_PER_FRAME = UINT_MAX; ///< You can optionally set this in order to limit changes per frame\n        static ui32 totalContainerCompressions = 1; ///< Set this to 1 each frame\n\n        template<typename T, size_t SIZE> class SmartVoxelContainer;\n\n        template<typename T, size_t SIZE>\n        class SmartHandle {\n            friend class SmartVoxelContainer<T, SIZE>;\n        public:\n            operator const T&() const;\n\n            SmartHandle& operator= (T data);\n            SmartHandle& operator= (const SmartHandle& o);\n\n            SmartHandle(SmartHandle&& o) :\n                m_container(o.m_container),\n                m_index(o.m_index) {\n                // TODO: Empty for now try to null it out\n            }\n            SmartHandle(const SmartHandle& o) = delete;\n            SmartHandle& operator= (SmartHandle&& o) = delete;\n        private:\n            SmartHandle(SmartVoxelContainer<T, SIZE>& container, size_t index) :\n                m_container(container),\n                m_index(index) {\n                // Empty\n            }\n\n            SmartVoxelContainer<T, SIZE>& m_container; ///< The parent container that created the handle\n            size_t m_index; ///< The index of this handle into the smart container\n        };\n\n        /// This should be called once per frame to reset totalContainerChanges\n        inline void clearContainerCompressionsCounter() {\n            totalContainerCompressions = 1; ///< Start at 1 so that integer overflow handles the default case\n        }\n\n        enum class VoxelStorageState {\n            FLAT_ARRAY = 0,\n            INTERVAL_TREE = 1\n        };\n\n        template <typename T, size_t SIZE = CHUNK_SIZE>\n        class SmartVoxelContainer {\n            friend class SmartHandle<T, SIZE>;\n        public:\n            /// Constructor\n            SmartVoxelContainer() {\n                // Empty\n            }\n            /*! @brief Construct the container with a provided recycler.\n            *\n            * @param arrayRecycler: The recycler to be used in place of the default generated recycler.\n            */\n            SmartVoxelContainer(vcore::FixedSizeArrayRecycler<SIZE, T>* arrayRecycler) {\n                setArrayRecycler(arrayRecycler);\n            }\n\n            /*! @brief Change the array recycler.\n            *\n            * @param arrayRecycler: The recycler to be used in place of the default generated recycler.\n            */\n            void setArrayRecycler(vcore::FixedSizeArrayRecycler<SIZE, T>* arrayRecycler) {\n                _arrayRecycler = arrayRecycler;\n            }\n\n            SmartHandle<T, SIZE> operator[] (size_t index) {\n                return std::move(SmartHandle<T, SIZE>(*this, index));\n            }\n            const T& operator[] (size_t index) const {\n                return (getters[(size_t)_state])(this, index);\n            }\n\n            /// Initializes the container\n            inline void init(VoxelStorageState state) {\n                _state = state;\n                if (_state == VoxelStorageState::FLAT_ARRAY) {\n                    _dataArray = _arrayRecycler->create();\n                }\n            }\n\n            /// Creates the tree using a sorted array of data. \n            /// The number of voxels should add up to CHUNK_SIZE\n            /// @param state: Initial state of the container\n            /// @param data: The sorted array used to populate the container\n            inline void initFromSortedArray(VoxelStorageState state,\n                                            const std::vector <typename IntervalTree<T>::LNode>& data) {\n                _state = state;\n                _accessCount = 0;\n                _quietFrames = 0;\n                if (_state == VoxelStorageState::INTERVAL_TREE) {\n                    _dataTree.initFromSortedArray(data);\n                    _dataTree.checkTreeValidity();\n                } else {\n                    _dataArray = _arrayRecycler->create();\n                    int index = 0;\n                    for (size_t i = 0; i < data.size(); i++) {\n                        for (int j = 0; j < data[i].length; j++) {\n                            _dataArray[index++] = data[i].data;\n                        }\n                    }\n                }\n            }\n            inline void initFromSortedArray(VoxelStorageState state,\n                                            const typename IntervalTree<T>::LNode data[], size_t size) {\n                _state = state;\n                _accessCount = 0;\n                _quietFrames = 0;\n                if (_state == VoxelStorageState::INTERVAL_TREE) {\n                    _dataTree.initFromSortedArray(data, size);\n                    _dataTree.checkTreeValidity();\n                } else {\n                    _dataArray = _arrayRecycler->create();\n                    int index = 0;\n                    for (size_t i = 0; i < size; i++) {\n                        for (int j = 0; j < data[i].length; j++) {\n                            _dataArray[index++] = data[i].data;\n                        }\n                    }\n                }\n            }\n\n            inline void changeState(VoxelStorageState newState, std::mutex& dataLock) {\n                if (newState == _state) return;\n                if (newState == VoxelStorageState::INTERVAL_TREE) {\n                    compress(dataLock);\n                } else {\n                    uncompress(dataLock);\n                }\n                _quietFrames = 0;\n                _accessCount = 0;\n            }\n\n            /// Updates the container. Call once per frame\n            /// @param dataLock: The mutex that guards the data\n            inline void update(std::mutex& dataLock) {\n                // If access count is higher than the threshold, this is not a quiet frame\n                if (_accessCount >= ACCESS_COUNT_UNTIL_DECOMPRESS) {\n                    _quietFrames = 0;\n                } else {\n                    _quietFrames++;\n                }\n\n                if (_state == VoxelStorageState::INTERVAL_TREE) {\n                    // Check if we should uncompress the data\n                    if (_quietFrames == 0) {\n                        uncompress(dataLock);\n                    }\n                } else {\n                    // Check if we should compress the data\n                    if (_quietFrames >= QUIET_FRAMES_UNTIL_COMPRESS && totalContainerCompressions <= MAX_COMPRESSIONS_PER_FRAME) {\n                        compress(dataLock);\n                    }\n                }\n                _accessCount = 0;\n            }\n\n            /// Clears the container and frees memory\n            inline void clear() {\n                _accessCount = 0;\n                _quietFrames = 0;\n                if (_state == VoxelStorageState::INTERVAL_TREE) {\n                    _dataTree.clear();\n                } else if (_dataArray) {\n                    _arrayRecycler->recycle(_dataArray);\n                    _dataArray = nullptr;\n                }\n            }\n\n            /// Uncompressed the interval tree into a buffer.\n            /// May only be called when getState() == VoxelStorageState::INTERVAL_TREE\n            /// or you will get a null access violation.\n            /// @param buffer: Buffer of memory to store the result\n            inline void uncompressIntoBuffer(T* buffer) { _dataTree.uncompressIntoBuffer(buffer); }\n\n            /// Getters\n            const VoxelStorageState& getState() const {\n                return _state;\n            }\n            T* getDataArray() {\n                return _dataArray;\n            }\n            const T* getDataArray() const {\n                return _dataArray;\n            }\n            IntervalTree<T>& getTree() {\n                return _dataTree;\n            }\n            const IntervalTree<T>& getTree() const {\n                return _dataTree;\n            }\n\n            /// Gets the element at index\n            /// @param index: must be (0, SIZE]\n            /// @return The element\n            inline const T& get(size_t index) const {\n                return (getters[(size_t)_state])(this, index);\n            }\n            /// Sets the element at index\n            /// @param index: must be (0, SIZE]\n            /// @param value: The value to set at index\n            inline void set(size_t index, T value) {\n                _accessCount++;\n                (setters[(size_t)_state])(this, index, value);\n            }\n        private:\n            typedef const T& (*Getter)(const SmartVoxelContainer*, size_t);\n            typedef void(*Setter)(SmartVoxelContainer*, size_t, T);\n\n            static const T& getInterval(const SmartVoxelContainer* container, size_t index) {\n                return container->_dataTree.getData(index);\n            }\n            static const T& getFlat(const SmartVoxelContainer* container, size_t index) {\n                return container->_dataArray[index];\n            }\n            static void setInterval(SmartVoxelContainer* container, size_t index, T data) {\n                container->_dataTree.insert(index, data);\n            }\n            static void setFlat(SmartVoxelContainer* container, size_t index, T data) {\n                container->_dataArray[index] = data;\n            }\n\n            static Getter getters[2];\n            static Setter setters[2];\n\n            inline void uncompress(std::mutex& dataLock) {\n                dataLock.lock();\n                _dataArray = _arrayRecycler->create();\n                uncompressIntoBuffer(_dataArray);\n                // Free memory\n                _dataTree.clear();\n                // Set the new state\n                _state = VoxelStorageState::FLAT_ARRAY;\n                dataLock.unlock();\n            }\n            inline void compress(std::mutex& dataLock) {\n                dataLock.lock();\n                // Sorted array for creating the interval tree\n                // Using stack array to avoid allocations, beware stack overflow\n                typename IntervalTree<T>::LNode data[CHUNK_SIZE];\n                int index = 0;\n                data[0].set(0, 1, _dataArray[0]);\n                // Set the data\n                for (int i = 1; i < CHUNK_SIZE; ++i) {\n                    if (_dataArray[i] == data[index].data) {\n                        ++(data[index].length);\n                    } else {\n                        data[++index].set(i, 1, _dataArray[i]);\n                    }\n                }\n                // Set new state\n                _state = VoxelStorageState::INTERVAL_TREE;\n                // Create the tree\n                _dataTree.initFromSortedArray(data, index + 1);\n\n                dataLock.unlock();\n\n                // Recycle memory\n                _arrayRecycler->recycle(_dataArray);\n                _dataArray = nullptr;\n\n                totalContainerCompressions++;\n            }\n\n            IntervalTree<T> _dataTree; ///< Interval tree of voxel data\n\n            T* _dataArray = nullptr; ///< pointer to an array of voxel data\n            int _accessCount = 0; ///< Number of times the container was accessed this frame\n            int _quietFrames = 0; ///< Number of frames since we have had heavy updates\n\n            VoxelStorageState _state = VoxelStorageState::FLAT_ARRAY; ///< Current data structure state\n\n            vcore::FixedSizeArrayRecycler<CHUNK_SIZE, T>* _arrayRecycler = nullptr; ///< For recycling the voxel arrays\n        };\n\n        /*template<typename T, size_t SIZE>\n        inline SmartHandle<T, SIZE>::operator const T&() const {\n            return m_container[m_index];\n        }*/\n        template<typename T, size_t SIZE>\n        inline SmartHandle<T, SIZE>::operator const T&() const {\n            return (m_container.getters[(size_t)m_container.getState()])(&m_container, m_index);\n        }\n        template<typename T, size_t SIZE>\n        inline SmartHandle<T, SIZE>& SmartHandle<T, SIZE>::operator= (T data) {\n            m_container.set(m_index, data);\n            return *this;\n        }\n        template<typename T, size_t SIZE>\n        inline SmartHandle<T, SIZE>& SmartHandle<T, SIZE>::operator= (const SmartHandle<T, SIZE>& o) {\n            m_container.set(m_index, o.m_container[o.m_index]);\n            return *this;\n        }\n\n        template<typename T, size_t SIZE>\n        typename SmartVoxelContainer<T, SIZE>::Getter SmartVoxelContainer<T, SIZE>::getters[2] = {\n            SmartVoxelContainer<T, SIZE>::getFlat,\n            SmartVoxelContainer<T, SIZE>::getInterval\n        };\n        template<typename T, size_t SIZE>\n        typename SmartVoxelContainer<T, SIZE>::Setter SmartVoxelContainer<T, SIZE>::setters[2] = {\n            SmartVoxelContainer<T, SIZE>::setFlat,\n            SmartVoxelContainer<T, SIZE>::setInterval\n        };\n\n    }\n}\nnamespace vvox = vorb::voxel;\n\n#endif // SmartVoxelContainer_h__"
  },
  {
    "path": "SoA/SoAState.h",
    "content": "///\n/// SoaState.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 10 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// The main game state for SoA\n///\n\n#pragma once\n\n#ifndef SoAState_h__\n#define SoAState_h__\n\n#include \"SpaceSystem.h\"\n#include \"GameSystem.h\"\n\n#include \"BlockPack.h\"\n#include \"ChunkAllocator.h\"\n#include \"ClientState.h\"\n#include \"Item.h\"\n\n#include \"ECSTemplates.h\"\n\n#include <Vorb/io/IOManager.h>\n#include <Vorb/ecs/Entity.h>\n#include <Vorb/VorbPreDecl.inl>\n\nclass PlanetGenLoader;\nclass SoaOptions;\nDECL_VIO(class IOManager);\n\nstruct SoaState {\n    SoaState() {}\n\n    SpaceSystem* spaceSystem = nullptr;\n    GameSystem* gameSystem = nullptr;\n\n    // TODO(Ben): Clean up this dumping ground\n    PagedChunkAllocator chunkAllocator;\n\n    ECSTemplateLibrary templateLib;\n    \n    // TODO(Ben): Move somewhere else.\n    ClientState clientState;\n\n    vio::IOManager* systemIoManager = nullptr;\n\n    vcore::ThreadPool<WorkerData>* threadPool = nullptr;\n\n    SoaOptions* options = nullptr; // Lives in App\n\n    BlockPack blocks;\n    ItemPack items;\n    \n    vio::IOManager saveFileIom;\n\n    f64 time = 0.0;\n    bool isInputEnabled = true;\n    float timeStep = 0.016f;\nprivate:\n    VORB_NON_COPYABLE(SoaState);\n};\n\n#endif // SoAState_h__\n"
  },
  {
    "path": "SoA/SoaController.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SoaController.h\"\n\n#include <Vorb/ecs/Entity.h>\n\n#include \"App.h\"\n#include \"GameSystemAssemblages.h\"\n#include \"GameSystemUpdater.h\"\n#include \"SoAState.h\"\n#include \"SoaOptions.h\"\n#include \"SoaEngine.h\"\n#include \"OrbitComponentUpdater.h\"\n\nSoaController::~SoaController() {\n    // Empty\n}\n\nvoid initCreativeInventory(vecs::EntityID eid, SoaState* state) {\n    auto& invCmp = state->gameSystem->inventory.getFromEntity(eid);\n    const std::vector<Block>& blocks = state->blocks.getBlockList();\n    // Skip first two blocks\n    for (size_t i = 2; i < blocks.size(); i++) {\n        if (!state->items.hasItem(i)) {\n            ItemData d;\n            d.blockID = i;\n            d.maxCount = UINT_MAX;\n            d.name = blocks[i].name;\n            d.type = ItemType::BLOCK;\n            // Add new item to stack\n            ItemStack stack;\n            stack.id = state->items.append(d);\n            stack.count = UINT_MAX;\n            stack.pack = &state->items;\n            invCmp.items.push_back(stack);\n        }\n    }\n}\n\nvoid SoaController::startGame(SoaState* state) {\n    // Load game ECS\n    SoaEngine::loadGameSystem(state);\n\n    GameSystem* gameSystem = state->gameSystem;\n    SpaceSystem* spaceSystem = state->spaceSystem;\n\n    // TODO(Ben): Client only\n    ClientState& clientState = state->clientState;\n    if (clientState.isNewGame) {\n        // Create the player entity and make the initial planet his parent\n        if (clientState.startingPlanet) {\n            clientState.playerEntity = state->templateLib.build(*gameSystem, \"Player\");\n\n            auto& spacePos = gameSystem->spacePosition.getFromEntity(clientState.playerEntity);\n            spacePos.position = clientState.startSpacePos;\n            spacePos.parentEntity = clientState.startingPlanet;\n            spacePos.parentGravity = spaceSystem->sphericalGravity.getComponentID(clientState.startingPlanet);\n            spacePos.parentSphericalTerrain = spaceSystem->sphericalTerrain.getComponentID(clientState.startingPlanet);\n        \n            auto& physics = gameSystem->physics.getFromEntity(clientState.playerEntity);\n            physics.spacePosition = gameSystem->spacePosition.getComponentID(clientState.playerEntity);\n        } else {\n            clientState.playerEntity = state->templateLib.build(*gameSystem, \"Player\");\n\n            auto& spacePos = gameSystem->spacePosition.getFromEntity(clientState.playerEntity);\n            spacePos.position = state->clientState.startSpacePos;\n        }\n\n        // TODO(Ben): Temporary\n        initCreativeInventory(clientState.playerEntity, state);\n    } else {\n        // TODO(Ben): This\n    }\n}\n\nf64v3 SoaController::getEntityEyeVoxelPosition(SoaState* state, vecs::EntityID eid) {\n    auto& hCmp = state->gameSystem->head.getFromEntity(eid);\n    auto& vpCmp = state->gameSystem->voxelPosition.get(hCmp.voxelPosition);\n    return vpCmp.gridPosition.pos + hCmp.relativePosition;\n}\n\nf64v3 SoaController::getEntityViewVoxelDirection(SoaState* state, vecs::EntityID eid) {\n    auto& hCmp = state->gameSystem->head.getFromEntity(eid);\n    auto& vpCmp = state->gameSystem->voxelPosition.get(hCmp.voxelPosition);\n    f64v3 v(0.0, 0.0, 1.0);\n    return vpCmp.orientation * hCmp.relativeOrientation * v;\n}\n"
  },
  {
    "path": "SoA/SoaController.h",
    "content": "///\n/// SoaController.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Main game controller for SoA\n///\n\n#pragma once\n\n#ifndef SoaController_h__\n#define SoaController_h__\n\nclass App;\nstruct SoaState;\n\n#include <Vorb/ecs/Entity.h>\n\nclass SoaController {\npublic:\n    virtual ~SoaController();\n    void startGame(SoaState* state);\n\n    f64v3 getEntityEyeVoxelPosition(SoaState* state, vecs::EntityID eid);\n    f64v3 getEntityViewVoxelDirection(SoaState* state, vecs::EntityID eid);\n};\n\n#endif // SoaController_h__\n"
  },
  {
    "path": "SoA/SoaEngine.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SoaEngine.h\"\n\n#include \"BlockData.h\"\n#include \"BlockPack.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkUpdater.h\"\n#include \"DebugRenderer.h\"\n#include \"GameSystemComponentBuilders.h\"\n#include \"PlanetGenLoader.h\"\n#include \"ProgramGenDelegate.h\"\n#include \"SoAState.h\"\n#include \"SpaceSystemAssemblages.h\"\n\n#define M_PER_KM 1000.0\n\nOptionsController SoaEngine::optionsController;\n\nvoid SoaEngine::initOptions(SoaOptions& options) {\n    options.addOption(OPT_PLANET_DETAIL, \"Planet Detail\", OptionValue(1));\n    options.addOption(OPT_VOXEL_RENDER_DISTANCE, \"Voxel Render Distance\", OptionValue(144.0f));\n    options.addOption(OPT_HUD_MODE, \"Hud Mode\", OptionValue(0));\n    options.addOption(OPT_TEXTURE_RES, \"Texture Resolution\", OptionValue(32));\n    options.addOption(OPT_MOTION_BLUR, \"Motion Blur\", OptionValue(0));\n    options.addOption(OPT_DEPTH_OF_FIELD, \"Depth Of Field\", OptionValue(0));\n    options.addOption(OPT_MSAA, \"MSAA\", OptionValue(0));\n    options.addOption(OPT_MAX_MSAA, \"Max MSAA\", OptionValue(8));\n    options.addOption(OPT_SPECULAR_EXPONENT, \"Specular Exponent\", OptionValue(8.0f));\n    options.addOption(OPT_SPECULAR_INTENSITY, \"Specular Intensity\", OptionValue(0.3f));\n    options.addOption(OPT_HDR_EXPOSURE, \"HDR Exposure\", OptionValue(0.5f)); //TODO(Ben): Useless?\n    options.addOption(OPT_GAMMA, \"Gamma\", OptionValue(1.0f));\n    options.addOption(OPT_SEC_COLOR_MULT, \"Sec Color Mult\", OptionValue(0.1f)); //TODO(Ben): Useless?\n    options.addOption(OPT_FOV, \"FOV\", OptionValue(70.0f));\n    options.addOption(OPT_VSYNC, \"VSYNC\", OptionValue(true));\n    options.addOption(OPT_MAX_FPS, \"Max FPS\", OptionValue(60.0f)); //TODO(Ben): appdata.config?\n    options.addOption(OPT_VOXEL_LOD_THRESHOLD, \"Voxel LOD Threshold\", OptionValue(128.0f));\n    options.addOption(OPT_MUSIC_VOLUME, \"Music Volume\", OptionValue(1.0f));\n    options.addOption(OPT_EFFECT_VOLUME, \"Effect Volume\", OptionValue(1.0f));\n    options.addOption(OPT_MOUSE_SENSITIVITY, \"Mouse Sensitivity\", OptionValue(1.0f));\n    options.addOption(OPT_INVERT_MOUSE, \"Invert Mouse\", OptionValue(false));\n    options.addOption(OPT_FULLSCREEN, \"Fullscreen\", OptionValue(false));\n    options.addOption(OPT_BORDERLESS, \"Borderless Window\", OptionValue(false));\n    options.addOption(OPT_SCREEN_WIDTH, \"Screen Width\", OptionValue(1280));\n    options.addOption(OPT_SCREEN_HEIGHT, \"Screen Height\", OptionValue(720));\n    options.addStringOption(\"Texture Pack\", \"Default\");\n\n    SoaEngine::optionsController.setDefault();\n}\n\nvoid SoaEngine::initState(SoaState* state) {\n    state->gameSystem = new GameSystem;\n    state->spaceSystem = new SpaceSystem;\n    state->systemIoManager = new vio::IOManager;\n\n    { // Threadpool init\n        size_t hc = std::thread::hardware_concurrency();\n        // Remove two threads for the render thread and main thread\n        if (hc > 1) hc--;\n        if (hc > 1) hc--;\n\n        // Drop a thread so we don't steal the hardware on debug\n#ifdef DEBUG\n        if (hc > 1) hc--;\n#endif\n\n        // Initialize the threadpool with hc threads\n        state->threadPool = new vcore::ThreadPool<WorkerData>();\n        state->threadPool->init(hc);\n    }\n\n    // Init ECS\n    // TODO(Ben): Mod packs\n    state->templateLib.registerFactory<AABBCollidableComponentBuilder>(GAME_SYSTEM_CT_AABBCOLLIDABLE_NAME);\n    state->templateLib.registerFactory<SpacePositionComponentBuilder>(GAME_SYSTEM_CT_SPACEPOSITION_NAME);\n    state->templateLib.registerFactory<VoxelPositionComponentBuilder>(GAME_SYSTEM_CT_VOXELPOSITION_NAME);\n    state->templateLib.registerFactory<PhysicsComponentBuilder>(GAME_SYSTEM_CT_PHYSICS_NAME);\n    state->templateLib.registerFactory<FrustumComponentBuilder>(GAME_SYSTEM_CT_FRUSTUM_NAME);\n    state->templateLib.registerFactory<HeadComponentBuilder>(GAME_SYSTEM_CT_HEAD_NAME);\n    state->templateLib.registerFactory<ParkourInputComponentBuilder>(GAME_SYSTEM_CT_PARKOURINPUT_NAME);\n    state->templateLib.registerFactory<AttributeComponentBuilder>(GAME_SYSTEM_CT_ATTRIBUTES_NAME);\n    state->templateLib.registerFactory<InventoryComponentBuilder>(GAME_SYSTEM_CT_INVENTORY_NAME);\n\n    { // Load ECS templates\n        vio::IOManager iom;\n        vio::DirectoryEntries entries;\n        iom.getDirectoryEntries(\"Data/ECS\", entries);\n        for (auto& p : entries) {\n            if (p.isFile()) state->templateLib.loadTemplate(p);\n        }\n    }\n\n    ChunkUpdater::blockPack = &state->blocks;\n\n    // TODO(Ben): Move somewhere else\n    initClientState(state, state->clientState);\n}\n\nvoid SoaEngine::initClientState(SoaState* soaState, ClientState& state) {\n    state.debugRenderer = new DebugRenderer;\n    state.chunkMeshManager = new ChunkMeshManager(soaState->threadPool, &soaState->blocks);\n    state.systemViewer = new MainMenuSystemViewer;\n    // TODO(Ben): This is also elsewhere?\n    state.texturePathResolver.init(\"Textures/TexturePacks/\" + soaOptions.getStringOption(\"Texture Pack\").defaultValue + \"/\",\n                                    \"Textures/TexturePacks/\" + soaOptions.getStringOption(\"Texture Pack\").value + \"/\");\n\n    // TODO(Ben): Don't hardcode this. Load a texture pack file\n    state.blockTextures = new BlockTexturePack;\n    state.blockTextures->init(32, 4096);\n    state.blockTextureLoader.init(&state.texturePathResolver, state.blockTextures);\n}\n\nbool SoaEngine::loadSpaceSystem(SoaState* state, const nString& filePath) {\n\n    AutoDelegatePool pool;\n    vpath path = \"SoASpace.log\";\n    vfile file;\n    path.asFile(&file);\n    vfstream fs = file.open(vio::FileOpenFlags::READ_WRITE_CREATE);\n    pool.addAutoHook(state->spaceSystem->onEntityAdded, [=] (Sender, vecs::EntityID eid) {\n        fs.write(\"Entity added: %d\\n\", eid);\n    });\n    for (auto namedTable : state->spaceSystem->getComponents()) {\n        auto table = state->spaceSystem->getComponentTable(namedTable.first);\n        pool.addAutoHook(table->onEntityAdded, [=] (Sender, vecs::ComponentID cid, vecs::EntityID eid) {\n            fs.write(\"Component \\\"%s\\\" added: %d -> Entity %d\\n\", namedTable.first.c_str(), cid, eid);\n        });\n    }\n\n    // Load system\n    SpaceSystemLoader spaceSystemLoader;\n    spaceSystemLoader.init(state);\n    spaceSystemLoader.loadStarSystem(filePath);\n\n    pool.dispose();\n    return true;\n}\n\nbool SoaEngine::loadGameSystem(SoaState* state VORB_UNUSED) {\n    // TODO(Ben): Implement and remove VORB_UNUSED tag.\n    \n    return true;\n}\n\n#define SET_RANGE(a, b, name) a.name.min = b.name.x; a.name.max = b.name.y;\n#define TRY_SET_BLOCK(id, bp, name) bp = blocks.hasBlock(name); if (bp) id = bp->ID;\n\ninline void setTreeFruitProperties(TreeTypeFruitProperties& fp, const FruitKegProperties& kp, const PlanetGenData* genData) {\n    SET_RANGE(fp, kp, chance);\n    auto it = genData->floraMap.find(kp.flora);\n    if (it != genData->floraMap.end()) {\n        fp.flora = it->second;\n    }\n}\n\nvoid setTreeLeafProperties(TreeTypeLeafProperties& lp, const LeafKegProperties& kp, const PlanetGenData* genData, const BlockPack& blocks) {\n    lp.type = kp.type;\n    setTreeFruitProperties(lp.fruitProps, kp.fruitProps, genData);\n    const Block* b;\n    switch (lp.type) {\n        case TreeLeafType::ROUND:\n            SET_RANGE(lp, kp, round.vRadius);\n            SET_RANGE(lp, kp, round.hRadius);\n            TRY_SET_BLOCK(lp.round.blockID, b, kp.block);\n            break;\n        case TreeLeafType::PINE:\n            SET_RANGE(lp, kp, pine.oRadius);\n            SET_RANGE(lp, kp, pine.iRadius);\n            SET_RANGE(lp, kp, pine.period);\n            TRY_SET_BLOCK(lp.pine.blockID, b, kp.block);\n            break;\n        case TreeLeafType::MUSHROOM:\n            SET_RANGE(lp, kp, mushroom.tvRadius);\n            SET_RANGE(lp, kp, mushroom.thRadius);\n            SET_RANGE(lp, kp, mushroom.bvRadius);\n            SET_RANGE(lp, kp, mushroom.bhRadius);\n            SET_RANGE(lp, kp, mushroom.bLength);\n            SET_RANGE(lp, kp, mushroom.capWidth);\n            SET_RANGE(lp, kp, mushroom.gillWidth);\n            lp.mushroom.interp = kp.mushroom.interp;\n            // Block overrides cap and gill when they are none\n            if (kp.block != \"none\" && kp.mushGillBlock == \"none\" && kp.mushCapBlock == \"none\") {\n                TRY_SET_BLOCK(lp.mushroom.gillBlockID, b, kp.block);\n                TRY_SET_BLOCK(lp.mushroom.capBlockID, b, kp.block);\n            } else {\n                TRY_SET_BLOCK(lp.mushroom.gillBlockID, b, kp.mushGillBlock);\n                TRY_SET_BLOCK(lp.mushroom.capBlockID, b, kp.mushCapBlock);\n            }\n            break;\n        case TreeLeafType::NONE:\n            break;\n    }\n}\n\nvoid setTreeBranchProperties(TreeTypeBranchProperties& bp, const BranchKegProperties& kp, const PlanetGenData* genData, const BlockPack& blocks) {\n    SET_RANGE(bp, kp, coreWidth);\n    SET_RANGE(bp, kp, barkWidth);\n    SET_RANGE(bp, kp, widthFalloff);\n    SET_RANGE(bp, kp, branchChance);\n    SET_RANGE(bp, kp, angle);\n    SET_RANGE(bp, kp, subBranchAngle);\n    SET_RANGE(bp, kp, changeDirChance);\n    const Block* b;\n    TRY_SET_BLOCK(bp.coreBlockID, b,kp.coreBlock);\n    TRY_SET_BLOCK(bp.barkBlockID, b, kp.barkBlock);\n    setTreeFruitProperties(bp.fruitProps, kp.fruitProps, genData);\n    setTreeLeafProperties(bp.leafProps, kp.leafProps, genData, blocks);\n}\n\nvoid SoaEngine::initVoxelGen(PlanetGenData* genData, const BlockPack& blocks) {\n    PlanetBlockInitInfo& blockInfo = genData->blockInfo;\n    if (genData) {\n        // Set all block layers\n        genData->blockLayers.resize(blockInfo.blockLayers.size());\n        for (size_t i = 0; i < blockInfo.blockLayers.size(); i++) {\n            BlockLayerKegProperties& kp = blockInfo.blockLayers[i];\n            BlockLayer& l = genData->blockLayers[i];\n            l.width = kp.width;\n            const Block* b = blocks.hasBlock(kp.block);\n            if (b) {\n                l.block = b->ID;\n            } else {\n                l.block = 0;\n            }\n            if (kp.surface.size()) {\n                b = blocks.hasBlock(kp.surface);\n                if (b) {\n                    l.surfaceTransform = b->ID;\n                } else {\n                    l.surfaceTransform = l.block;\n                }\n            } else {\n                l.surfaceTransform = l.block;\n            }\n        }\n        // Set starts for binary search application\n        int start = 0;\n        for (auto& l : genData->blockLayers) {\n            l.start = start;\n            start += l.width;\n        }\n\n        // Set liquid block\n        if (blockInfo.liquidBlockName.length()) {\n            if (blocks.hasBlock(blockInfo.liquidBlockName)) {\n                genData->liquidBlock = blocks[blockInfo.liquidBlockName].ID;\n            }\n        }\n        // Set surface block\n        if (blockInfo.surfaceBlockName.length()) {\n            if (blocks.hasBlock(blockInfo.surfaceBlockName)) {\n                genData->surfaceBlock = blocks[blockInfo.surfaceBlockName].ID;\n            }\n        }\n\n        // Set flora data\n        genData->flora.resize(blockInfo.flora.size());\n        for (size_t i = 0; i < blockInfo.flora.size(); i++) {\n            FloraKegProperties& kp = blockInfo.flora[i];\n            const Block* b = blocks.hasBlock(kp.block);\n            if (b) {\n                FloraType& ft = genData->flora[i];\n                genData->floraMap[kp.id] = i;\n                ft.block = b->ID;\n                ft.height.min = kp.height.x;\n                ft.height.max = kp.height.y;\n                ft.slope.min = kp.slope.x;\n                ft.slope.max = kp.slope.y;\n                ft.dSlope.min = kp.dSlope.x;\n                ft.dSlope.max = kp.dSlope.y;\n                ft.dir = kp.dir;\n            }\n        }\n        // Set sub-flora\n        for (size_t i = 0; i < genData->flora.size(); i++) {\n            FloraKegProperties& kp = blockInfo.flora[i];\n            FloraType& ft = genData->flora[i];\n            if (kp.nextFlora.size()) {\n                auto it = genData->floraMap.find(kp.nextFlora);\n                if (it != genData->floraMap.end()) {\n                    ft.nextFlora = &genData->flora[it->second];\n                } else {\n                    ft.nextFlora = nullptr;\n                }\n            } else {\n                ft.nextFlora = nullptr;\n            }\n        }\n\n        // Set tree types\n        genData->trees.resize(blockInfo.trees.size());\n        for (size_t i = 0; i < blockInfo.trees.size(); ++i) {\n            NTreeType& td = genData->trees[i];\n            const TreeKegProperties& kp = blockInfo.trees[i];\n            // Add to lookup map\n            genData->treeMap[kp.id] = i;\n            // Set height range\n            SET_RANGE(td, kp, height);\n            SET_RANGE(td, kp, branchPoints);\n            SET_RANGE(td, kp, branchStep);\n            SET_RANGE(td, kp, killMult);\n            SET_RANGE(td, kp, infRadius);\n            // Set branch volume properties\n            td.branchVolumes.resize(kp.branchVolumes.size());\n            for (size_t j = 0; j < kp.branchVolumes.size(); j++) {\n                TreeTypeBranchVolumeProperties& tp = td.branchVolumes[j];\n                const BranchVolumeKegProperties& tkp = kp.branchVolumes[j];\n                SET_RANGE(tp, tkp, height);\n                SET_RANGE(tp, tkp, hRadius);\n                SET_RANGE(tp, tkp, vRadius);\n                SET_RANGE(tp, tkp, points);\n            }\n            // Set trunk properties\n            td.trunkProps.resize(kp.trunkProps.size());\n            for (size_t j = 0; j < kp.trunkProps.size(); j++) {\n                TreeTypeTrunkProperties& tp = td.trunkProps[j];\n                const TrunkKegProperties& tkp = kp.trunkProps[j];\n                const Block* b;\n                tp.loc = tkp.loc;\n                TRY_SET_BLOCK(tp.barkBlockID, b, tkp.barkBlock);\n                TRY_SET_BLOCK(tp.coreBlockID, b, tkp.coreBlock);\n                // Set ranges\n                SET_RANGE(tp, tkp, coreWidth);\n                SET_RANGE(tp, tkp, barkWidth);\n                SET_RANGE(tp, tkp, branchChance);\n                SET_RANGE(tp, tkp, changeDirChance);\n                tp.slope.min.min = tkp.slope[0].x;\n                tp.slope.min.max = tkp.slope[0].y;\n                tp.slope.max.min = tkp.slope[1].x;\n                tp.slope.max.max = tkp.slope[1].y;\n                tp.interp = tkp.interp;\n                setTreeFruitProperties(tp.fruitProps, tkp.fruitProps, genData);\n                setTreeBranchProperties(tp.branchProps, tkp.branchProps, genData, blocks);\n                setTreeLeafProperties(tp.leafProps, tkp.leafProps, genData, blocks);\n            }\n        }\n\n        // Set biome trees and flora\n        for (auto& biome : genData->biomes) {\n            biome.genData = genData;\n            { // Flora\n                auto it = blockInfo.biomeFlora.find(&biome);\n                if (it != blockInfo.biomeFlora.end()) {\n                    auto& kList = it->second;\n                    biome.flora.resize(kList.size());\n                    // Iterate through keg properties\n                    for (size_t i = 0; i < kList.size(); i++) {\n                        auto& kp = kList[i];\n                        auto mit = genData->floraMap.find(kp.id);\n                        if (mit != genData->floraMap.end()) {\n                            biome.flora[i].chance = kp.chance;\n                            biome.flora[i].data = &genData->flora[mit->second];\n                            biome.flora[i].id = i;\n                        } else {\n                            fprintf(stderr, \"Failed to find flora id %s\", kp.id.c_str());\n                        }\n                    }\n                }\n            }\n            { // Trees\n                auto it = blockInfo.biomeTrees.find(&biome);\n                if (it != blockInfo.biomeTrees.end()) {\n                    auto& kList = it->second;\n                    biome.trees.resize(kList.size());\n                    // Iterate through keg properties\n                    for (size_t i = 0; i < kList.size(); i++) {\n                        auto& kp = kList[i];\n                        auto mit = genData->treeMap.find(kp.id);\n                        if (mit != genData->treeMap.end()) {\n                            biome.trees[i].chance = kp.chance;\n                            biome.trees[i].data = &genData->trees[mit->second];\n                            // Trees and flora share IDs so we can use a single\n                            // value in heightmap. Thus, add flora.size().\n                            biome.trees[i].id = biome.flora.size() + i;\n                        } else {\n                            fprintf(stderr, \"Failed to find flora id %s\", kp.id.c_str());\n                        }\n                    }\n                }\n            }\n        }\n\n        // Clear memory\n        blockInfo = PlanetBlockInitInfo();\n    }\n}\n#undef SET_RANGE\n\n// TODO: Investigate why glRPC isn't currently being used.\nvoid SoaEngine::reloadSpaceBody(SoaState* state, vecs::EntityID eid, vcore::RPCManager* glRPC VORB_UNUSED) {\n    SpaceSystem* spaceSystem = state->spaceSystem;\n    auto& stCmp = spaceSystem->sphericalTerrain.getFromEntity(eid);\n    f64 radius = stCmp.radius;\n    auto npCmpID = stCmp.namePositionComponent;\n    auto arCmpID = stCmp.axisRotationComponent;\n    auto ftCmpID = stCmp.farTerrainComponent;\n    WorldCubeFace face = WorldCubeFace::FACE_NONE;\n    PlanetGenData* genData = stCmp.planetGenData;\n    nString filePath = genData->terrainFilePath;\n\n    if (ftCmpID) {\n        face = spaceSystem->farTerrain.getFromEntity(eid).face;\n        SpaceSystemAssemblages::removeFarTerrainComponent(spaceSystem, eid);\n    }\n    if (stCmp.sphericalVoxelComponent) {\n        SpaceSystemAssemblages::removeSphericalVoxelComponent(spaceSystem, eid);\n    }\n\n    SpaceSystemAssemblages::removeSphericalTerrainComponent(spaceSystem, eid);\n    //state->planetLoader->textureCache.freeTexture(genData->liquidColorMap);\n   // state->planetLoader->textureCache.freeTexture(genData->terrainColorMap);\n    PlanetGenLoader loader;\n    loader.init(state->systemIoManager);\n    genData = loader.loadPlanetGenData(filePath);\n    genData->radius = radius;\n\n    auto stCmpID = SpaceSystemAssemblages::addSphericalTerrainComponent(spaceSystem, eid, npCmpID, arCmpID,\n                                                         radius,\n                                                         genData,\n                                                         state->threadPool);\n    if (ftCmpID) {\n        auto ftCmpID = SpaceSystemAssemblages::addFarTerrainComponent(spaceSystem, eid, stCmp, face);\n        stCmp.farTerrainComponent = ftCmpID;\n       \n    }\n\n    // TODO(Ben): this doesn't work too well.\n    auto& pCmp = state->gameSystem->spacePosition.getFromEntity(state->clientState.playerEntity);\n    pCmp.parentSphericalTerrain = stCmpID;\n    pCmp.parentGravity = spaceSystem->sphericalGravity.getComponentID(eid);\n    pCmp.parentEntity = eid;\n}\n\nvoid SoaEngine::destroyAll(SoaState* state) {\n    delete state->spaceSystem;\n    delete state->gameSystem;\n    delete state->systemIoManager;\n    delete state->options;\n    destroyClientState(state->clientState);\n    destroyGameSystem(state);\n    destroySpaceSystem(state);\n}\n\nvoid SoaEngine::destroyClientState(ClientState& state) {\n    delete state.debugRenderer;\n    delete state.chunkMeshManager;\n    delete state.systemViewer;\n    delete state.blockTextures;\n}\n\nvoid SoaEngine::destroyGameSystem(SoaState* state) {\n    delete state->gameSystem;\n}\n\nvoid SoaEngine::destroySpaceSystem(SoaState* state) {\n    delete state->spaceSystem;\n}\n\n"
  },
  {
    "path": "SoA/SoaEngine.h",
    "content": "///\n/// SoAEngine.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 10 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Handles initialization and destruction of SoAState\n///\n\n#pragma once\n\n#ifndef SoAEngine_h__\n#define SoAEngine_h__\n\n#include <Vorb/ecs/Entity.h>\n#include <Vorb/VorbPreDecl.inl>\n#include \"OptionsController.h\"\n#include \"SpaceSystemLoader.h\"\n\nclass GameSystem;\nclass BlockPack;\nclass SpaceSystem;\nstruct SoaState;\nstruct ClientState;\nstruct PlanetGenData;\n\nDECL_VCORE(class RPCManager)\n\n#pragma once\nclass SoaEngine {\npublic:\n\n    /// Initializes the default SoaOptions\n    static void initOptions(SoaOptions& options);\n\n    /// Initializes SoaState resources\n    static void initState(SoaState* state);\n\n    static void initClientState(SoaState* soaState, ClientState& state);\n    \n    /// Loads and initializes the SpaceSystem\n    static bool loadSpaceSystem(SoaState* state, const nString& filePath);\n\n    /// Loads and initializes the GameSystem\n    static bool loadGameSystem(SoaState* state);\n\n    /// Sets block IDs for planet data\n    static void initVoxelGen(PlanetGenData* genData, const BlockPack& blocks);\n\n    static void reloadSpaceBody(SoaState* state, vecs::EntityID eid, vcore::RPCManager* glRPC);\n\n    /// Destroys the SoaState completely\n    static void destroyAll(SoaState* state);\n\n    static void destroyClientState(ClientState& state);\n\n    static void destroyGameSystem(SoaState* state);\n\n    static void destroySpaceSystem(SoaState* state);\n\n    static OptionsController optionsController;\n};\n\n#endif // SoAEngine_h__\n"
  },
  {
    "path": "SoA/SoaFileSystem.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SoaFileSystem.h\"\n\nvoid SoaFileSystem::init() {\n    m_roots[\"Music\"] = vio::IOManager(\"Data/Music\");\n\n}\n\nconst vio::IOManager& SoaFileSystem::get(const nString& name) const {\n    return m_roots.at(name);\n}\n\n"
  },
  {
    "path": "SoA/SoaFileSystem.h",
    "content": "///\n/// SoaFilesystem.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 11 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Provides utilities for operating within the SoA filesystem\n///\n\n#pragma once\n\n#ifndef SoaFilesystem_h__\n#define SoaFilesystem_h__\n\n#include <Vorb/io/IOManager.h>\n\nclass SoaFileSystem {\npublic:\n    void init();\n\n    const vio::IOManager& get(const nString& name) const;\nprivate:\n    std::unordered_map<nString, vio::IOManager> m_roots; ///< IOManagers mapped by friendly file system names\n};\n\n\n#endif // SoaFilesystem_h__\n"
  },
  {
    "path": "SoA/SoaOptions.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SoaOptions.h\"\n\n#include <SDL2/SDL.h>\n#include <Vorb/io/IOManager.h>\n\n#include \"GameManager.h\"\n#include \"InputMapper.h\"\n\nSoaOptions soaOptions;\n\nSoaOptions::SoaOptions() {\n    m_options.reserve(OPT_NUM_OPTIONS);\n}\n\nSoaOptions::~SoaOptions() {\n    // Empty\n}\n\nvoid SoaOptions::addOption(int id, const nString& name, OptionValue defaultValue, SoaOptionFlags flags) {\n    if (id >= (int)m_options.size()) {\n        m_options.resize(id + 1);\n        m_options[id].id = id;\n        m_options[id].name = name;\n        m_options[id].defaultValue = defaultValue;\n        m_options[id].value = defaultValue;\n        m_options[id].flags = flags;\n        m_optionsLookup[name] = id;\n    }\n}\n\nvoid SoaOptions::addOption(const nString& name, OptionValue defaultValue, SoaOptionFlags flags) {\n    m_options.emplace_back();\n    SoaOption& option = m_options.back();\n    option.id = m_options.size() - 1;\n    option.name = name;\n    option.defaultValue = defaultValue;\n    option.value = defaultValue;\n    option.flags = flags;\n    m_optionsLookup[name] = option.id;\n}\n\nvoid SoaOptions::addStringOption(const nString& name, const nString& defaultValue) {\n    SoaStringOption option;\n    option.name = name;\n    option.defaultValue = defaultValue;\n    option.value = defaultValue;\n    m_stringOptionsLookup[name] = option;\n}\n\nint SoaOptions::findID(const nString& name) {\n    auto it = m_optionsLookup.find(name);\n    if (it == m_optionsLookup.end()) return -1;\n    return it->second;\n}\n\nSoaOption* SoaOptions::find(const nString& name) {\n    auto it = m_optionsLookup.find(name);\n    if (it == m_optionsLookup.end()) return nullptr;\n    return &m_options[it->second];\n}\n\nSoaOption& SoaOptions::get(int id) {\n    return m_options.at(id);\n}\n\nSoaOption& SoaOptions::get(const nString& name) {\n    return m_options.at(m_optionsLookup[name]);\n}\n\nSoaStringOption& SoaOptions::getStringOption(const nString& name) {\n    return m_stringOptionsLookup[name];\n}\n\nvoid SoaOptions::dispose() {\n    std::vector<SoaOption>().swap(m_options);\n    std::map<nString, int>().swap(m_optionsLookup);\n    std::map<nString, SoaStringOption>().swap(m_stringOptionsLookup);\n}\n"
  },
  {
    "path": "SoA/SoaOptions.h",
    "content": "#pragma once\n#include \"Errors.h\"\n\nstruct SoaOptionFlags {\n    bool needsWindowReload : 1;\n    bool needsFBOReload : 1;\n    bool needsShaderReload : 1;\n    bool needsTextureReload : 1;\n};\n\nenum class OptionValueType {\n    NONE,\n    F32,\n    I32,\n    BOOL,\n    CHAR\n};\n\nstruct OptionValue {\n    OptionValue() {}\n    OptionValue(f32 f) : f(f), type(OptionValueType::F32) {}\n    OptionValue(i32 i) : i(i), type(OptionValueType::I32) {}\n    OptionValue(bool b) : b(b), type(OptionValueType::BOOL) {}\n    OptionValue(char c) : c(c), type(OptionValueType::CHAR) {}\n    union {\n        f32 f;\n        i32 i;\n        bool b;\n        char c;\n    };\n    OptionValueType type = OptionValueType::NONE;\n};\n\nstruct SoaOption {\n    int id = -1;\n    nString name = \"\";\n    OptionValue defaultValue;\n    OptionValue value;\n    SoaOptionFlags flags;\n};\nstruct SoaStringOption {\n    nString name;\n    nString defaultValue;\n    nString value;\n};\n\n// Integer IDs for faster default options lookups\nenum DefaultOptions : int {\n    OPT_PLANET_DETAIL = 0,\n    OPT_VOXEL_RENDER_DISTANCE,\n    OPT_HUD_MODE,\n    OPT_TEXTURE_RES,\n    OPT_MOTION_BLUR,\n    OPT_DEPTH_OF_FIELD,\n    OPT_MSAA,\n    OPT_MAX_MSAA,\n    OPT_SPECULAR_EXPONENT,\n    OPT_SPECULAR_INTENSITY,\n    OPT_HDR_EXPOSURE,\n    OPT_GAMMA,\n    OPT_SEC_COLOR_MULT,\n    OPT_FOV,\n    OPT_VSYNC,\n    OPT_MAX_FPS,\n    OPT_VOXEL_LOD_THRESHOLD,\n    OPT_MUSIC_VOLUME,\n    OPT_EFFECT_VOLUME,\n    OPT_MOUSE_SENSITIVITY,\n    OPT_INVERT_MOUSE,\n    OPT_FULLSCREEN,\n    OPT_BORDERLESS,\n    OPT_SCREEN_WIDTH,\n    OPT_SCREEN_HEIGHT,\n    OPT_NUM_OPTIONS // This should be last\n};\n\nclass SoaOptions {\npublic:\n    SoaOptions();\n    ~SoaOptions();\n\n    void addOption(int id, const nString& name, OptionValue defaultValue, SoaOptionFlags flags = {});\n    void addOption(const nString& name, OptionValue defaultValue, SoaOptionFlags flags = {});\n    void addStringOption(const nString& name, const nString& defaultValue);\n \n    int findID(const nString& name);\n    SoaOption* find(const nString& name);\n    SoaOption& get(int id);\n    SoaOption& get(const nString& name);\n    SoaStringOption& getStringOption(const nString& name);\n\n    const std::vector<SoaOption>& getOptions() const { return m_options; }\n\n    const nString& getFilePath() const { return m_filePath; }\n\n    void dispose();\nprivate:\n    std::vector<SoaOption> m_options;\n    // String lookups are slower than int lookups\n    std::map<nString, int> m_optionsLookup;\n    std::map<nString, SoaStringOption> m_stringOptionsLookup;\n    nString m_filePath = \"Data/options.ini\";\n};\n\n// Global options struct\nextern SoaOptions soaOptions;"
  },
  {
    "path": "SoA/SoaState.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SoAState.h\"\n\n#include <Vorb/io/IOManager.h>\n\n#include \"DebugRenderer.h\"\n#include \"PlanetGenLoader.h\"\n#include \"ChunkMeshManager.h\"\n#include \"PlanetGenLoader.h\"\n"
  },
  {
    "path": "SoA/SonarRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SonarRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"BlockPack.h\"\n#include \"BlockTexturePack.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkRenderer.h\"\n#include \"GameRenderParams.h\"\n#include \"SoaOptions.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n\n// TODO(Ben): Don't hardcode\nconst f32 SONAR_DISTANCE = 200.0f;\nconst f32 SONAR_WIDTH = 30.0f;\n\nSonarRenderStage::SonarRenderStage(const GameRenderParams* gameRenderParams) :\n    m_gameRenderParams(gameRenderParams) {\n    // Empty\n}\n\nvoid SonarRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    glDisable(GL_DEPTH_TEST);\n    ChunkMeshManager* cmm = m_gameRenderParams->chunkMeshmanager;\n\n    if (!m_program.isCreated()) {\n        m_program = ShaderLoader::createProgramFromFile(\"Shaders/BlockShading/standardShading.vert\",\n                                                             \"Shaders/BlockShading/sonarShading.frag\");\n    }\n    m_program.use();\n    m_program.enableVertexAttribArrays();\n\n    // Bind the block textures\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D_ARRAY, m_gameRenderParams->blockTexturePack->getAtlasTexture());\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ChunkRenderer::sharedIBO);\n\n    glUniform1f(m_program.getUniform(\"sonarDistance\"), SONAR_DISTANCE);\n    glUniform1f(m_program.getUniform(\"waveWidth\"), SONAR_WIDTH);\n    glUniform1f(m_program.getUniform(\"dt\"), 1.0f);\n\n    glUniform1f(m_program.getUniform(\"fadeDistance\"), ChunkRenderer::fadeDist);\n\n    glDisable(GL_CULL_FACE);\n    glDepthMask(GL_FALSE);\n    const std::vector <ChunkMesh *>& chunkMeshes = cmm->getChunkMeshes();\n    {\n        std::lock_guard<std::mutex> l(cmm->lckActiveChunkMeshes);\n        if (chunkMeshes.empty()) return;\n        for (unsigned int i = 0; i < chunkMeshes.size(); i++) {\n            ChunkRenderer::drawOpaqueCustom(chunkMeshes[i], m_program,\n                                            m_gameRenderParams->chunkCamera->getPosition(),\n                                            m_gameRenderParams->chunkCamera->getViewProjectionMatrix());\n        }\n    }\n\n    glDepthMask(GL_TRUE);\n    glEnable(GL_CULL_FACE);\n\n    m_program.unuse();\n    glEnable(GL_DEPTH_TEST);\n}"
  },
  {
    "path": "SoA/SonarRenderStage.h",
    "content": "/// \n///  SonarRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file implements the sonar render stage which does a cool\n///  sonar rendering effect.\n///\n\n#pragma once\n\n#ifndef SonarRenderStage_h__\n#define SonarRenderStage_h__\n\n#include \"IRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\nclass Camera;\nclass GameRenderParams;\nclass MeshManager;\n\nclass SonarRenderStage : public IRenderStage\n{\npublic:\n    /// Constructor which injects dependencies\n    /// @param camera: The camera handle\n    /// @param meshManager: Handle to the class that holds meshes\n    SonarRenderStage(const GameRenderParams* gameRenderParams);\n\n    // Draws the render stage\n    virtual void render(const Camera* camera) override;\nprivate:\n    vg::GLProgram m_program;\n    const GameRenderParams* m_gameRenderParams; ///< Handle to shared parameters\n};\n\n#endif // SonarRenderStage_h__\n"
  },
  {
    "path": "SoA/SpaceSystem.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"SpaceSystem.h\"\n\n#include <Vorb/TextureRecycler.hpp>\n#include <Vorb/graphics/GLProgram.h>\n\nSpaceSystem::SpaceSystem() : vecs::ECS() {\n    // Add in component tables\n    addComponentTable(SPACE_SYSTEM_CT_NAMEPOSITIION_NAME, &namePosition);\n    addComponentTable(SPACE_SYSTEM_CT_AXISROTATION_NAME, &axisRotation);\n    addComponentTable(SPACE_SYSTEM_CT_ORBIT_NAME, &orbit);\n    addComponentTable(SPACE_SYSTEM_CT_SPHERICALTERRAIN_NAME, &sphericalTerrain);\n    addComponentTable(SPACE_SYSTEM_CT_GASGIANT_NAME, &gasGiant);\n    addComponentTable(SPACE_SYSTEM_CT_STAR_NAME, &star);\n    addComponentTable(SPACE_SYSTEM_CT_FARTERRAIN_NAME, &farTerrain);\n    addComponentTable(SPACE_SYSTEM_CT_SPHERICALGRAVITY_NAME, &sphericalGravity);\n    addComponentTable(SPACE_SYSTEM_CT_SPHERICALVOXEL_NAME, &sphericalVoxel);\n    addComponentTable(SPACE_SYSTEM_CT_SPACELIGHT_NAME, &spaceLight);\n    addComponentTable(SPACE_SYSTEM_CT_ATMOSPHERE_NAME, &atmosphere);\n    addComponentTable(SPACE_SYSTEM_CT_PLANETRINGS_NAME, &planetRings);\n    addComponentTable(SPACE_SYSTEM_CT_CLOUDS_NAME, &clouds);\n}\n\nSpaceSystem::~SpaceSystem() {\n\n    for (auto& it : sphericalVoxel) {\n        sphericalVoxel.disposeComponent(sphericalVoxel.getComponentID(it.first), it.first);\n    }\n    for (auto& it : orbit) {\n        orbit.disposeComponent(orbit.getComponentID(it.first), it.first);\n    }\n    for (auto& it : sphericalVoxel) {\n        sphericalVoxel.disposeComponent(sphericalVoxel.getComponentID(it.first), it.first);\n    }\n    for (auto& it : sphericalTerrain) {\n        sphericalTerrain.disposeComponent(sphericalTerrain.getComponentID(it.first), it.first);\n    }\n}\n\nvecs::ComponentID SpaceSystem::getComponent(nString name, vecs::EntityID eID) {\n    auto& table = *getComponentTable(name);\n    return table.getComponentID(eID);\n}"
  },
  {
    "path": "SoA/SpaceSystem.h",
    "content": "///\n/// SpaceSystem.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Implementation of a Star System with ECS\n///\n\n#pragma once\n\n#ifndef SpaceSystem_h__\n#define SpaceSystem_h__\n\n#include \"SpaceSystemComponents.h\"\n#include \"SpaceSystemComponentTables.h\"\n\n#include <Vorb/io/IOManager.h>\n#include <Vorb/ecs/ComponentTable.hpp>\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/GLProgram.h>\n\n#define SPACE_SYSTEM_CT_NAMEPOSITIION_NAME \"NamePosition\"\n#define SPACE_SYSTEM_CT_AXISROTATION_NAME \"AxisRotation\"\n#define SPACE_SYSTEM_CT_ORBIT_NAME \"Orbit\"\n#define SPACE_SYSTEM_CT_SPHERICALTERRAIN_NAME \"SphericalTerrain\"\n#define SPACE_SYSTEM_CT_FARTERRAIN_NAME \"FarTerrain\"\n#define SPACE_SYSTEM_CT_SPHERICALGRAVITY_NAME \"SphericalGravity\"\n#define SPACE_SYSTEM_CT_GASGIANT_NAME \"GasGiant\"\n#define SPACE_SYSTEM_CT_STAR_NAME \"Star\"\n#define SPACE_SYSTEM_CT_SPHERICALVOXEL_NAME \"SphericalVoxel\"\n#define SPACE_SYSTEM_CT_SPACELIGHT_NAME \"SpaceLight\"\n#define SPACE_SYSTEM_CT_ATMOSPHERE_NAME \"Atmosphere\"\n#define SPACE_SYSTEM_CT_PLANETRINGS_NAME \"PlanetRings\"\n#define SPACE_SYSTEM_CT_CLOUDS_NAME \"Clouds\"\n\nclass App;\nclass Binary;\nclass Camera;\nclass GameSystem;\nclass PlanetGenLoader;\nstruct SoaState;\nclass SpriteBatch;\nclass SpriteFont;\nstruct GasGiantProperties;\nstruct PlanetProperties;\nstruct StarProperties;\nstruct SystemBody;\nstruct SystemOrbitProperties;\n\nDECL_VG(class TextureRecycler)\n\nclass SpaceSystem : public vecs::ECS {\n    friend class SpaceSystemRenderStage;\n    friend class MainMenuSystemViewer;\npublic:\n    SpaceSystem();\n    ~SpaceSystem();\n\n    NamePositionComponentTable namePosition;\n    AxisRotationComponentTable axisRotation;\n    OrbitComponentTable orbit;\n    SphericalGravityComponentTable sphericalGravity;\n    SphericalTerrainComponentTable sphericalTerrain;\n    GasGiantComponentTable gasGiant;\n    StarComponentTable star;\n    FarTerrainComponentTable farTerrain;\n    SpaceLightComponentTable spaceLight;\n    AtmosphereComponentTable atmosphere;\n    PlanetRingsComponentTable planetRings;\n    CloudsComponentTable clouds;\n    SphericalVoxelComponentTable sphericalVoxel;\n    \n    f32 age = 0.0f; ///< age of the system\n    nString systemDescription = \"No description\"; ///< textual description of the system\n\n    // vVv   TODO(Cristian): Holy fuck, get rid of these from here   vVv\n    std::map<nString, std::pair<f32v4, f32v4> > pathColorMap; ///< Map of body type to path colors\n\n    vecs::ComponentID getComponent(nString name, vecs::EntityID eID);\n\nprivate:\n    VORB_NON_COPYABLE(SpaceSystem);\n};\n\n#endif // SpaceSystem_h__\n"
  },
  {
    "path": "SoA/SpaceSystemAssemblages.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SpaceSystemAssemblages.h\"\n\n#include \"ChunkGrid.h\"\n#include \"ChunkIOManager.h\"\n#include \"ChunkAllocator.h\"\n#include \"FarTerrainPatch.h\"\n#include \"OrbitComponentUpdater.h\"\n#include \"SoAState.h\"\n#include \"SpaceSystem.h\"\n#include \"SphericalTerrainComponentUpdater.h\"\n#include \"SphericalHeightmapGenerator.h\"\n\n#include \"TerrainPatchMeshManager.h\"\n#include \"SpaceSystemAssemblages.h\"\n#include \"SpaceSystemLoadStructs.h\"\n\n// TEMPORARY\n#include \"GameManager.h\"\n#include \"PlanetGenData.h\"\n\n#define SEC_PER_HOUR 3600.0\n\nEvent<SphericalVoxelComponent&, vecs::EntityID> SpaceSystemAssemblages::onAddSphericalVoxelComponent;\nEvent<SphericalVoxelComponent&, vecs::EntityID> SpaceSystemAssemblages::onRemoveSphericalVoxelComponent;\n\nvecs::EntityID SpaceSystemAssemblages::createOrbit(SpaceSystem* spaceSystem,\n                                                   const SystemOrbitProperties* sysProps,\n                                                   SystemBody* body, f64 bodyRadius) {\n    body->entity = spaceSystem->addEntity();\n    const vecs::EntityID& id = body->entity;\n\n    f64v3 tmpPos(0.0);\n    vecs::ComponentID npCmp = addNamePositionComponent(spaceSystem, id, body->name, tmpPos);\n\n    SpaceSystemAssemblages::addOrbitComponent(spaceSystem, id, npCmp, sysProps->type, sysProps->e,\n                                              sysProps->t, sysProps->n, sysProps->p,\n                                              sysProps->i, sysProps->a);\n\n    addSphericalGravityComponent(spaceSystem, id, npCmp, bodyRadius, body->mass);\n\n    return id;\n}\n\nvecs::EntityID SpaceSystemAssemblages::createPlanet(SpaceSystem* spaceSystem,\n                                    const SystemOrbitProperties* sysProps,\n                                    const PlanetProperties* properties,\n                                    SystemBody* body,\n                                    vcore::ThreadPool<WorkerData>* threadPool) {\n    body->entity = spaceSystem->addEntity();\n    const vecs::EntityID& id = body->entity;\n\n    // const f64v3 up(0.0, 1.0, 0.0);\n    vecs::ComponentID arCmp = addAxisRotationComponent(spaceSystem, id, properties->aTilt, properties->lNorth,\n                                                       0.0, properties->rotationalPeriod * SEC_PER_HOUR);\n\n    f64v3 tmpPos(0.0);\n    vecs::ComponentID npCmp = addNamePositionComponent(spaceSystem, id, body->name, tmpPos);\n\n    addSphericalTerrainComponent(spaceSystem, id, npCmp, arCmp,\n                                 properties->diameter * 0.5,\n                                 properties->planetGenData,\n                                 threadPool);\n\n    f64 planetRadius = properties->diameter / 2.0;\n    addSphericalGravityComponent(spaceSystem, id, npCmp, planetRadius, properties->mass);\n\n    const AtmosphereProperties& at = properties->atmosphere;\n    // Check if its active\n    if (at.scaleDepth != -1.0f) {\n        addAtmosphereComponent(spaceSystem, id, npCmp, (f32)planetRadius, (f32)(planetRadius * 1.025),\n                               at.kr, at.km, at.g, at.scaleDepth,\n                               at.waveLength);\n    }\n\n    const CloudsProperties& cl = properties->clouds;\n\n    if (cl.density > 0.0f) {\n        addCloudsComponent(spaceSystem, id, npCmp, (f32)planetRadius, (f32)(planetRadius * 0.0075), cl.color, cl.scale, cl.density);\n    }\n\n    SpaceSystemAssemblages::addOrbitComponent(spaceSystem, id, npCmp, sysProps->type, sysProps->e,\n                                              sysProps->t, sysProps->n, sysProps->p,\n                                              sysProps->i, sysProps->a);\n\n    return id;\n}\n\nvoid SpaceSystemAssemblages::destroyPlanet(SpaceSystem* gameSystem VORB_UNUSED, vecs::EntityID planetEntity VORB_UNUSED) {\n    // TODO: implement and remove VORB_UNUSED tags.\n}\n\nvecs::EntityID SpaceSystemAssemblages::createStar(SpaceSystem* spaceSystem,\n                                  const SystemOrbitProperties* sysProps,\n                                  const StarProperties* properties,\n                                  SystemBody* body) {\n    body->entity = spaceSystem->addEntity();\n    const vecs::EntityID& id = body->entity;\n\n    // const f64v3 up(0.0, 1.0, 0.0);\n    vecs::ComponentID arCmp = addAxisRotationComponent(spaceSystem, id, properties->aTilt, properties->lNorth,\n                                                       0.0, properties->rotationalPeriod * SEC_PER_HOUR);\n\n    f64v3 tmpPos(0.0);\n    vecs::ComponentID npCmp = addNamePositionComponent(spaceSystem, id, body->name, tmpPos);\n\n    f64 radius = properties->diameter / 2.0;\n    addStarComponent(spaceSystem, id, npCmp, arCmp, properties->mass, radius, properties->surfaceTemperature);\n\n    addSpaceLightComponent(spaceSystem, id, npCmp, color3(255, 255, 255), 1.0f);\n\n    addSphericalGravityComponent(spaceSystem, id, npCmp, radius, properties->mass);\n\n    SpaceSystemAssemblages::addOrbitComponent(spaceSystem, id, npCmp, sysProps->type, sysProps->e,\n                                                     sysProps->t, sysProps->n, sysProps->p,\n                                                     sysProps->i, sysProps->a);\n\n    return id;\n}\n\nvoid SpaceSystemAssemblages::destroyStar(SpaceSystem* gameSystem VORB_UNUSED, vecs::EntityID planetEntity VORB_UNUSED) {\n    // TODO: implement and remove VORB_UNUSED tags.\n}\n\n/// GasGiant entity\nvecs::EntityID SpaceSystemAssemblages::createGasGiant(SpaceSystem* spaceSystem,\n                                      const SystemOrbitProperties* sysProps,\n                                      const GasGiantProperties* properties,\n                                      SystemBody* body) {\n    body->entity = spaceSystem->addEntity();\n    const vecs::EntityID& id = body->entity;\n\n    // const f64v3 up(0.0, 1.0, 0.0);\n    vecs::ComponentID arCmp = addAxisRotationComponent(spaceSystem, id, properties->aTilt, properties->lNorth,\n                                                       0.0, properties->rotationalPeriod * SEC_PER_HOUR);\n\n    f64v3 tmpPos(0.0);\n    vecs::ComponentID npCmp = addNamePositionComponent(spaceSystem, id, body->name, tmpPos);\n\n    f64 radius = properties->diameter / 2.0;\n    addGasGiantComponent(spaceSystem, id, npCmp, arCmp, properties->oblateness, radius,\n                         properties->colorMap, properties->rings);\n\n    addSphericalGravityComponent(spaceSystem, id, npCmp, radius, properties->mass);\n\n    const AtmosphereProperties& at = properties->atmosphere;\n    // Check if its active\n    if (at.scaleDepth != -1.0f) {\n        addAtmosphereComponent(spaceSystem, id, npCmp, (f32)radius, (f32)(radius * 1.025),\n                               at.kr, at.km, at.g, at.scaleDepth,\n                               at.waveLength, properties->oblateness);\n    }\n\n    if (properties->rings.size()) {\n        addPlanetRingsComponent(spaceSystem, id, npCmp, properties->rings);\n    }\n\n    SpaceSystemAssemblages::addOrbitComponent(spaceSystem, id, npCmp, sysProps->type, sysProps->e,\n                                                     sysProps->t, sysProps->n, sysProps->p,\n                                                     sysProps->i, sysProps->a);\n\n    return id;\n}\n\nvoid SpaceSystemAssemblages::destroyGasGiant(SpaceSystem* gameSystem VORB_UNUSED, vecs::EntityID planetEntity VORB_UNUSED) {\n    // TODO: implement and remove VORB_UNUSED tags.\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addAtmosphereComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                                 vecs::ComponentID namePositionComponent, f32 planetRadius,\n                                                                 f32 radius, f32 kr, f32 km, f32 g, f32 scaleDepth,\n                                                                 f32v3 wavelength, f32 oblateness /*= 0.0f*/) {\n    vecs::ComponentID aCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_ATMOSPHERE_NAME, entity);\n    auto& aCmp = spaceSystem->atmosphere.get(aCmpId);\n    aCmp.namePositionComponent = namePositionComponent;\n    aCmp.planetRadius = planetRadius;\n    aCmp.radius = radius;\n    aCmp.oblateness = oblateness;\n    aCmp.kr = kr;\n    aCmp.km = km;\n    aCmp.g = g;\n    aCmp.scaleDepth = scaleDepth;\n    aCmp.invWavelength4 = f32v3(1.0f / powf(wavelength.r, 4.0f),\n                                1.0f / powf(wavelength.g, 4.0f),\n                                1.0f / powf(wavelength.b, 4.0f));\n    return aCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeAtmosphereComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_ATMOSPHERE_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addPlanetRingsComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                          vecs::ComponentID namePositionComponent, const Array<PlanetRingProperties>& rings) {\n    vecs::ComponentID prCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_PLANETRINGS_NAME, entity);\n    if (prCmpId == 0) {\n        return 0;\n    }\n    auto& prCmp = spaceSystem->planetRings.get(prCmpId);\n    prCmp.namePositionComponent = namePositionComponent;\n    prCmp.rings.resize(rings.size());\n    for (size_t i = 0; i < rings.size(); i++) {\n        auto& r1 = prCmp.rings[i];\n        auto& r2 = rings[i];\n        r1.innerRadius = r2.innerRadius;\n        r1.outerRadius = r2.outerRadius;\n        r1.texturePath = r2.colorLookup;\n        r1.orientation = glm::angleAxis((f64)r2.lNorth, f64v3(0.0, 1.0, 0.0)) * glm::angleAxis((f64)r2.aTilt, f64v3(1.0, 0.0, 0.0));\n    }\n    return prCmpId;\n}\n\nvoid  SpaceSystemAssemblages::removePlanetRingsComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_PLANETRINGS_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addCloudsComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                            vecs::ComponentID namePositionComponent, f32 planetRadius,\n                                                            f32 height, f32v3 color, f32v3 scale, float density) {\n\n    vecs::ComponentID cCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_CLOUDS_NAME, entity);\n    auto& cCmp = spaceSystem->clouds.get(cCmpId);\n    cCmp.namePositionComponent = namePositionComponent;\n    cCmp.planetRadius = planetRadius;\n    cCmp.height = height;\n    cCmp.color = color;\n    cCmp.scale = scale;\n    cCmp.density = density;\n    return cCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeCloudsComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_CLOUDS_NAME, entity);\n}\n\n// TODO: Is this implementation complete?\nvecs::ComponentID SpaceSystemAssemblages::addSphericalVoxelComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                                      vecs::ComponentID sphericalTerrainComponent,\n                                                                      vecs::ComponentID farTerrainComponent,\n                                                                      vecs::ComponentID axisRotationComponent,\n                                                                      vecs::ComponentID namePositionComponent,\n                                                                      WorldCubeFace worldFace VORB_UNUSED,\n                                                                      SoaState* soaState) {\n\n    vecs::ComponentID svCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_SPHERICALVOXEL_NAME, entity);\n    if (svCmpId == 0) {\n        return 0;\n    }\n    auto& svcmp = spaceSystem->sphericalVoxel.get(svCmpId);\n\n    auto& ftcmp = spaceSystem->farTerrain.get(farTerrainComponent);\n\n    // Get component handles\n    svcmp.sphericalTerrainComponent = sphericalTerrainComponent;\n    svcmp.axisRotationComponent = axisRotationComponent;\n    svcmp.namePositionComponent = namePositionComponent;\n    svcmp.farTerrainComponent = farTerrainComponent;\n\n    svcmp.voxelRadius = ftcmp.sphericalTerrainData->radius * VOXELS_PER_KM;\n\n    svcmp.generator = ftcmp.cpuGenerator;\n    svcmp.chunkIo = new ChunkIOManager(\"TESTSAVEDIR\"); // TODO(Ben): Fix\n    svcmp.blockPack = &soaState->blocks;\n\n    svcmp.threadPool = soaState->threadPool;\n\n    svcmp.chunkIo->beginThread();\n\n    svcmp.chunkGrids = new ChunkGrid[6];\n    for (int i = 0; i < 6; i++) {\n        svcmp.chunkGrids[i].init(static_cast<WorldCubeFace>(i), svcmp.threadPool, 1, ftcmp.planetGenData, &soaState->chunkAllocator);\n        svcmp.chunkGrids[i].blockPack = &soaState->blocks;\n    }\n\n    svcmp.planetGenData = ftcmp.planetGenData;\n    svcmp.sphericalTerrainData = ftcmp.sphericalTerrainData;\n    svcmp.saveFileIom = &soaState->saveFileIom;\n\n    onAddSphericalVoxelComponent(svcmp, entity);\n    return svCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeSphericalVoxelComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    onRemoveSphericalVoxelComponent(spaceSystem->sphericalVoxel.getFromEntity(entity), entity);\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_SPHERICALVOXEL_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addAxisRotationComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                                  f32 aTilt, f32 lNorth, f64 startAngle,\n                                                                  f64 rotationalPeriod) {\n    vecs::ComponentID arCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_AXISROTATION_NAME, entity);\n    auto& arCmp = spaceSystem->axisRotation.get(arCmpId);\n    arCmp.tilt = aTilt;\n    arCmp.axisOrientation = glm::angleAxis((f64)lNorth, f64v3(0.0, 1.0, 0.0)) * glm::angleAxis((f64)aTilt, f64v3(1.0, 0.0, 0.0));\n    arCmp.currentRotation = startAngle;\n    arCmp.period = rotationalPeriod;\n    return arCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeAxisRotationComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_AXISROTATION_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addSphericalTerrainComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                                      vecs::ComponentID npComp,\n                                                                      vecs::ComponentID arComp,\n                                                                      f64 radius,\n                                                                      PlanetGenData* planetGenData,\n                                                                      vcore::ThreadPool<WorkerData>* threadPool) {\n    vecs::ComponentID stCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_SPHERICALTERRAIN_NAME, entity);\n    auto& stCmp = spaceSystem->sphericalTerrain.get(stCmpId);\n    \n    stCmp.namePositionComponent = npComp;\n    stCmp.axisRotationComponent = arComp;\n    stCmp.planetGenData = planetGenData;\n\n    if (planetGenData) {\n        stCmp.meshManager = new TerrainPatchMeshManager(planetGenData);\n        stCmp.cpuGenerator = new SphericalHeightmapGenerator;\n        stCmp.cpuGenerator->init(planetGenData);\n    }\n    \n    stCmp.radius = radius;\n    stCmp.alpha = 1.0f;\n\n    f64 patchWidth = (radius * 2.0) / ST_PATCH_ROW;\n    stCmp.sphericalTerrainData = new TerrainPatchData(radius, patchWidth, stCmp.cpuGenerator,\n                                                      stCmp.meshManager, threadPool);\n\n    return stCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeSphericalTerrainComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    // auto& stcmp = spaceSystem->sphericalTerrain.getFromEntity(entity);\n\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_SPHERICALTERRAIN_NAME, entity);\n}\n\n/// Star Component\nvecs::ComponentID SpaceSystemAssemblages::addStarComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                          vecs::ComponentID npComp,\n                                          vecs::ComponentID arComp,\n                                          f64 mass,\n                                          f64 radius,\n                                          f64 temperature) {\n    vecs::ComponentID sCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_STAR_NAME, entity);\n    auto& sCmp = spaceSystem->star.get(sCmpId);\n\n    sCmp.namePositionComponent = npComp;\n    sCmp.axisRotationComponent = arComp;\n    sCmp.radius = radius;\n    sCmp.temperature = temperature;\n    sCmp.mass = mass;\n    sCmp.occlusionQuery[0] = 0;\n    sCmp.occlusionQuery[1] = 0;\n\n    return sCmpId;\n}\nvoid SpaceSystemAssemblages::removeStarComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_STAR_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addGasGiantComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                               vecs::ComponentID npComp,\n                                                               vecs::ComponentID arComp,\n                                                               f32 oblateness,\n                                                               f64 radius,\n                                                               const nString& colorMapPath,\n                                                               const Array<PlanetRingProperties>& rings) {\n    vecs::ComponentID ggCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_GASGIANT_NAME, entity);\n    auto& ggCmp = spaceSystem->gasGiant.get(ggCmpId);\n\n    ggCmp.namePositionComponent = npComp;\n    ggCmp.axisRotationComponent = arComp;\n    ggCmp.oblateness = oblateness;\n    ggCmp.radius = radius;\n    ggCmp.colorMapPath = colorMapPath;\n    ggCmp.rings = rings;\n    return ggCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeGasGiantComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_GASGIANT_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addFarTerrainComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                                  SphericalTerrainComponent& parentCmp,\n                                                                  WorldCubeFace face) {\n    vecs::ComponentID ftCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_FARTERRAIN_NAME, entity);\n    auto& ftCmp = spaceSystem->farTerrain.get(ftCmpId);\n\n    ftCmp.planetGenData = parentCmp.planetGenData;\n    ftCmp.meshManager = parentCmp.meshManager;\n    ftCmp.cpuGenerator = parentCmp.cpuGenerator;\n    ftCmp.sphericalTerrainData = parentCmp.sphericalTerrainData;\n\n    ftCmp.face = face;\n    ftCmp.alpha = TERRAIN_INC_START_ALPHA;\n\n    return ftCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeFarTerrainComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    auto& ftcmp = spaceSystem->farTerrain.getFromEntity(entity);\n\n    if (ftcmp.patches) delete[] ftcmp.patches;\n    ftcmp.patches = nullptr;\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_FARTERRAIN_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addSphericalGravityComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                                        vecs::ComponentID npComp, f64 radius, f64 mass) {\n    vecs::ComponentID sgCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_SPHERICALGRAVITY_NAME, entity);\n    auto& sgCmp = spaceSystem->sphericalGravity.get(sgCmpId);\n    sgCmp.namePositionComponent = npComp;\n    sgCmp.radius = radius;\n    sgCmp.mass = mass;\n    return sgCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeSphericalGravityComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_SPHERICALGRAVITY_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addNamePositionComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                                  const nString& name, const f64v3& position) {\n    vecs::ComponentID npCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_NAMEPOSITIION_NAME, entity);\n    auto& npCmp = spaceSystem->namePosition.get(npCmpId);\n    npCmp.name = name;\n    npCmp.position = position;\n    return npCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeNamePositionComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_NAMEPOSITIION_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addOrbitComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                            vecs::ComponentID npComp, SpaceObjectType oType,\n                                                            f64 eccentricity, f64 orbitalPeriod,\n                                                            f64 ascendingLong, f64 periapsisLong,\n                                                            f64 inclination, f64 trueAnomaly) {\n    vecs::ComponentID oCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_ORBIT_NAME, entity);\n    auto& oCmp = spaceSystem->orbit.get(oCmpId);\n    oCmp.e = eccentricity;\n    oCmp.t = orbitalPeriod;\n    oCmp.npID = npComp;\n    oCmp.o = ascendingLong * DEG_TO_RAD;\n    oCmp.p = periapsisLong * DEG_TO_RAD;\n    oCmp.i = inclination * DEG_TO_RAD;\n    oCmp.startMeanAnomaly = trueAnomaly * DEG_TO_RAD;\n    oCmp.type = oType;\n\n    // Get the path color\n    std::pair<f32v4, f32v4> pathColor(f32v4(0.0f), f32v4(0.0f));\n    switch (oType) {\n        case SpaceObjectType::STAR:\n            pathColor = spaceSystem->pathColorMap[\"Star\"]; break;\n        case SpaceObjectType::PLANET:\n            pathColor = spaceSystem->pathColorMap[\"Planet\"]; break;\n        case SpaceObjectType::DWARF_PLANET:\n            pathColor = spaceSystem->pathColorMap[\"DwarfPlanet\"]; break;\n        case SpaceObjectType::MOON:\n            pathColor = spaceSystem->pathColorMap[\"Moon\"]; break;\n        case SpaceObjectType::DWARF_MOON:\n            pathColor = spaceSystem->pathColorMap[\"DwarfMoon\"]; break;\n        case SpaceObjectType::ASTEROID:\n            pathColor = spaceSystem->pathColorMap[\"Asteroid\"]; break;\n        case SpaceObjectType::COMET:\n            pathColor = spaceSystem->pathColorMap[\"Comet\"]; break;\n        default:\n            break;\n    }\n    oCmp.pathColor[0] = pathColor.first;\n    oCmp.pathColor[1] = pathColor.second;\n\n    return oCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeOrbitComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_ORBIT_NAME, entity);\n}\n\nvecs::ComponentID SpaceSystemAssemblages::addSpaceLightComponent(SpaceSystem* spaceSystem, vecs::EntityID entity, vecs::ComponentID npCmp, color3 color, f32 intensity) {\n    vecs::ComponentID slCmpId = spaceSystem->addComponent(SPACE_SYSTEM_CT_SPACELIGHT_NAME, entity);\n    auto& slCmp = spaceSystem->spaceLight.get(slCmpId);\n    slCmp.color = color;\n    slCmp.intensity = intensity;\n    slCmp.npID = npCmp;\n    return slCmpId;\n}\n\nvoid SpaceSystemAssemblages::removeSpaceLightComponent(SpaceSystem* spaceSystem, vecs::EntityID entity) {\n    spaceSystem->deleteComponent(SPACE_SYSTEM_CT_SPACELIGHT_NAME, entity);\n}\n"
  },
  {
    "path": "SoA/SpaceSystemAssemblages.h",
    "content": "///\n/// SpaceSystemAssemblages.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 13 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Component and entity assemblages for SpaceSystem\n///\n\n#pragma once\n\n#ifndef SpaceSystemAssemblages_h__\n#define SpaceSystemAssemblages_h__\n\nclass SpaceSystem;\n\n#include \"VoxelCoordinateSpaces.h\"\n#include \"SpaceSystemLoadStructs.h\"\n#include \"VoxPool.h\"\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/ecs/Entity.h>\n#include <Vorb/graphics/gtypes.h>\n\nstruct PlanetGenData;\nstruct GasGiantProperties;\nstruct PlanetProperties;\nstruct SoaState;\nstruct SphericalTerrainComponent;\nstruct SphericalVoxelComponent;\nstruct StarProperties;\nstruct SystemBody;\nstruct SystemOrbitProperties;\n\nDECL_VG(\n    class GLProgram;\n    class TextureRecycler;\n)\nDECL_VVOX(class VoxelMapData);\n\nenum class SpaceObjectType;\n\nnamespace SpaceSystemAssemblages {\n    /************************************************************************/\n    /* Entity Factories                                                     */\n    /************************************************************************/\n   \n    // Plain orbit entity\n    extern vecs::EntityID createOrbit(SpaceSystem* spaceSystem,\n                                       const SystemOrbitProperties* sysProps,\n                                       SystemBody* body, f64 bodyRadius);\n\n    /// Planet entity\n    extern vecs::EntityID createPlanet(SpaceSystem* spaceSystem,\n                                        const SystemOrbitProperties* sysProps,\n                                        const PlanetProperties* properties,\n                                        SystemBody* body,\n                                        vcore::ThreadPool<WorkerData>* threadPool);\n    extern void destroyPlanet(SpaceSystem* gameSystem, vecs::EntityID planetEntity);\n\n    /// Star entity\n    extern vecs::EntityID createStar(SpaceSystem* spaceSystem,\n                                        const SystemOrbitProperties* sysProps,\n                                        const StarProperties* properties,\n                                        SystemBody* body);\n    extern void destroyStar(SpaceSystem* gameSystem, vecs::EntityID planetEntity);\n\n    /// GasGiant entity\n    extern vecs::EntityID createGasGiant(SpaceSystem* spaceSystem,\n                                        const SystemOrbitProperties* sysProps,\n                                        const GasGiantProperties* properties,\n                                        SystemBody* body);\n    extern void destroyGasGiant(SpaceSystem* gameSystem, vecs::EntityID planetEntity);\n\n    /************************************************************************/\n    /* Component Assemblages                                                */\n    /************************************************************************/\n    /// Atmosphere component\n    extern vecs::ComponentID addAtmosphereComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                    vecs::ComponentID namePositionComponent, f32 planetRadius,\n                                                    f32 radius, f32 kr, f32 km, f32 g, f32 scaleDepth,\n                                                    f32v3 wavelength, f32 oblateness = 0.0f);\n    extern void removeAtmosphereComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// PlanetRings component\n    extern vecs::ComponentID addPlanetRingsComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                    vecs::ComponentID namePositionComponent, const Array<PlanetRingProperties>& rings);\n    extern void removePlanetRingsComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Clouds component\n    extern vecs::ComponentID addCloudsComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                    vecs::ComponentID namePositionComponent, f32 planetRadius,\n                                                    f32 height, f32v3 color, f32v3 scale, float density);\n    extern void removeCloudsComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Spherical voxel component\n    extern vecs::ComponentID addSphericalVoxelComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                         vecs::ComponentID sphericalTerrainComponent,\n                                                         vecs::ComponentID farTerrainComponent,\n                                                         vecs::ComponentID axisRotationComponent,\n                                                         vecs::ComponentID namePositionComponent,\n                                                         WorldCubeFace worldFace,\n                                                         SoaState* soaState);\n    extern void removeSphericalVoxelComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n    extern Event<SphericalVoxelComponent&, vecs::EntityID> onAddSphericalVoxelComponent;\n    extern Event<SphericalVoxelComponent&, vecs::EntityID> onRemoveSphericalVoxelComponent;\n\n    /// Axis rotation component\n    extern vecs::ComponentID addAxisRotationComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                      f32 aTilt, f32 lNorth,\n                                                      f64 startAngle,\n                                                      f64 rotationalPeriod);\n    extern void removeAxisRotationComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Spherical terrain component\n    extern vecs::ComponentID addSphericalTerrainComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                           vecs::ComponentID npComp,\n                                                           vecs::ComponentID arComp,\n                                                           f64 radius,\n                                                           PlanetGenData* planetGenData,\n                                                           vcore::ThreadPool<WorkerData>* threadPool);\n    extern void removeSphericalTerrainComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Star Component\n    extern vecs::ComponentID addStarComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                              vecs::ComponentID npComp,\n                                              vecs::ComponentID arComp,\n                                              f64 mass,\n                                              f64 radius,\n                                              f64 temperature);\n    extern void removeStarComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Gas giant component\n    extern vecs::ComponentID addGasGiantComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                  vecs::ComponentID npComp,\n                                                  vecs::ComponentID arComp,\n                                                  f32 oblateness,\n                                                  f64 radius,\n                                                  const nString& colorMapPath,\n                                                  const Array<PlanetRingProperties>& rings);\n    extern void removeGasGiantComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Far terrain component\n    extern vecs::ComponentID addFarTerrainComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                     SphericalTerrainComponent& parentCmp,\n                                                     WorldCubeFace face);\n    extern void removeFarTerrainComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Spherical Gravity component\n    extern vecs::ComponentID addSphericalGravityComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                           vecs::ComponentID npComp, f64 radius, f64 mass);\n    extern void removeSphericalGravityComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Name Position component\n    extern vecs::ComponentID addNamePositionComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                           const nString& name, const f64v3& position);\n    extern void removeNamePositionComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Orbit component\n    extern vecs::ComponentID addOrbitComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                               vecs::ComponentID npComp, SpaceObjectType oType,\n                                               f64 eccentricity, f64 orbitalPeriod,\n                                               f64 ascendingLong, f64 periapsisLong,\n                                               f64 inclination, f64 trueAnomaly);\n    extern void removeOrbitComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n\n    /// Space Light Component\n    extern vecs::ComponentID addSpaceLightComponent(SpaceSystem* spaceSystem, vecs::EntityID entity,\n                                                     vecs::ComponentID npCmp, color3 color, f32 intensity);\n    extern void removeSpaceLightComponent(SpaceSystem* spaceSystem, vecs::EntityID entity);\n}\n\n#endif // SpaceSystemAssemblages_h__"
  },
  {
    "path": "SoA/SpaceSystemComponentBuilders.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SpaceSystemComponentBuilders.h\"\n"
  },
  {
    "path": "SoA/SpaceSystemComponentBuilders.h",
    "content": "#pragma once\n#ifndef SpaceSystemComponentBuilders_h__\n#define SpaceSystemComponentBuilders_h__\n\n\n\n#endif //SpaceSystemComponentBuilders_h__"
  },
  {
    "path": "SoA/SpaceSystemComponentTables.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SpaceSystemComponentTables.h\"\n\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/ShaderManager.h>\n\n#include \"ChunkAllocator.h\"\n#include \"ChunkIOManager.h\"\n#include \"FarTerrainPatch.h\"\n#include \"ChunkGrid.h\"\n#include \"PlanetGenData.h\"\n#include \"SphericalHeightmapGenerator.h\"\n#include \"TerrainPatch.h\"\n#include \"TerrainPatchMeshManager.h\"\n\nvoid SphericalVoxelComponentTable::disposeComponent(vecs::ComponentID cID, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    SphericalVoxelComponent& cmp = _components[cID].second;\n    // Let the threadpool finish\n    while (cmp.threadPool->getTasksSizeApprox() > 0);\n    delete cmp.chunkIo;\n    delete[] cmp.chunkGrids;\n    cmp = _components[0].second;\n}\n\nvoid SphericalTerrainComponentTable::disposeComponent(vecs::ComponentID cID, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    SphericalTerrainComponent& cmp = _components[cID].second;\n    if (cmp.patches) {\n        delete[] cmp.patches;\n        cmp.patches = nullptr;\n    }\n    if (cmp.planetGenData) {\n        delete cmp.meshManager;\n        delete cmp.cpuGenerator;\n    }\n    // TODO(Ben): Memory leak\n    delete cmp.sphericalTerrainData;\n}\n\nvoid FarTerrainComponentTable::disposeComponent(vecs::ComponentID cID, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    FarTerrainComponent& cmp = _components[cID].second;  \n    if (cmp.patches) {\n        delete[] cmp.patches;\n        cmp.patches = nullptr;\n    }\n}\n\nvoid OrbitComponentTable::disposeComponent(vecs::ComponentID cID, vecs::EntityID eID VORB_MAYBE_UNUSED) {\n    OrbitComponent& cmp = _components[cID].second;\n    if (cmp.vbo) {\n        vg::GpuMemory::freeBuffer(cmp.vbo);\n    }\n}\n"
  },
  {
    "path": "SoA/SpaceSystemComponentTables.h",
    "content": "///\n/// SpaceSystemComponentTables.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 15 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// File for component tables that need custom deletion\n///\n\n#pragma once\n\n#ifndef SpaceSystemComponentTables_h__\n#define SpaceSystemComponentTables_h__\n\n#include <Vorb/ecs/ComponentTable.hpp>\n#include \"SpaceSystemComponents.h\"\n\nclass SphericalVoxelComponentTable : public vecs::ComponentTable<SphericalVoxelComponent> {\npublic:\n    virtual void disposeComponent(vecs::ComponentID cID, vecs::EntityID eID) override;\n};\n\nclass SphericalTerrainComponentTable : public vecs::ComponentTable < SphericalTerrainComponent > {\npublic:\n    virtual void disposeComponent(vecs::ComponentID cID, vecs::EntityID eID) override;\n};\n\nclass FarTerrainComponentTable : public vecs::ComponentTable < FarTerrainComponent > {\npublic:\n    virtual void disposeComponent(vecs::ComponentID cID, vecs::EntityID eID) override;\n};\n\nclass OrbitComponentTable : public vecs::ComponentTable < OrbitComponent > {\npublic:\n    virtual void disposeComponent(vecs::ComponentID cID, vecs::EntityID eID) override;\n};\n\n#endif // SpaceSystemComponentTables_h__\n"
  },
  {
    "path": "SoA/SpaceSystemComponents.h",
    "content": "///\n/// SpaceSystemComponents.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 20 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Component definitions for SpaceSystem\n///\n\n#pragma once\n\n#ifndef SpaceSystemComponents_h__\n#define SpaceSystemComponents_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/ecs/Entity.h>\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/concurrentqueue.h>\n\n#include <Vorb/io/Keg.h>\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/ecs/ComponentTable.hpp>\n\n#include \"Constants.h\"\n#include \"SpaceSystemLoadStructs.h\"\n#include \"VoxPool.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"VoxelLightEngine.h\"\n#include \"ChunkGrid.h\"\n\nclass BlockPack;\nclass ChunkIOManager;\nclass ChunkManager;\nclass FarTerrainPatch;\nclass PagedChunkAllocator;\nclass ParticleEngine;\nclass PhysicsEngine;\nclass SphericalHeightmapGenerator;\nclass SphericalTerrainGpuGenerator;\nclass TerrainPatch;\nclass TerrainPatchMeshManager;\nclass TerrainRpcDispatcher;\nstruct PlanetGenData;\nstruct TerrainPatchData;\n\nDECL_VVOX(class VoxelPlanetMapper);\nDECL_VIO(class IOManager);\n\n/// For far and spherical terrain patch blending on transitions\nconst f32 TERRAIN_FADE_LENGTH = 2.0f;\nconst f32 TERRAIN_ALPHA_BEFORE_FADE = 2.0f;\nconst f32 TERRAIN_DEC_START_ALPHA = TERRAIN_ALPHA_BEFORE_FADE + TERRAIN_FADE_LENGTH;\nconst f32 TERRAIN_INC_START_ALPHA = -TERRAIN_ALPHA_BEFORE_FADE;\nconst f32 TERRAIN_ALPHA_STEP = 0.01f;\n\nconst f32 START_FACE_TRANS = 1.0f;\n\nstruct AtmosphereComponent {\n    vecs::ComponentID namePositionComponent = 0;\n    f32 planetRadius;\n    f32 radius;\n    f32 oblateness = 0.0f;\n    f32 kr = 0.0025f;\n    f32 km = 0.0020f;\n    f32 esun = 30.0f; // TODO(Ben): This should be dynamic\n    f32 g = -0.99f;\n    f32 scaleDepth = 0.25f;\n    f32v3 invWavelength4 = f32v3(1.0f / powf(0.65f, 4.0f),\n                                 1.0f / powf(0.57f, 4.0f),\n                                 1.0f / powf(0.475f, 4.0f));\n};\ntypedef vecs::ComponentTable<AtmosphereComponent> AtmosphereComponentTable;\nKEG_TYPE_DECL(AtmosphereComponent);\n\nstruct CloudsComponent {\n    vecs::ComponentID namePositionComponent = 0;\n    f32 planetRadius;\n    f32 height;\n    f32v3 color;\n    f32v3 scale;\n    float density;\n};\ntypedef vecs::ComponentTable<CloudsComponent> CloudsComponentTable;\nKEG_TYPE_DECL(CloudsComponent);\n\n\nstruct AxisRotationComponent {\n    f64q axisOrientation; ///< Axis of rotation\n    f64q currentOrientation; ///< Current orientation with axis and rotation\n    f64q invCurrentOrientation; ///< Inverse of currentOrientation\n    f64 period = 0.0; ///< Period of rotation in seconds\n    f64 currentRotation = 0.0; ///< Current rotation about axis in radians\n    f32 tilt = 0.0f;\n};\ntypedef vecs::ComponentTable<AxisRotationComponent> AxisRotationComponentTable;\nKEG_TYPE_DECL(AxisRotationComponent);\n\nstruct NamePositionComponent {\n    f64v3 position = f64v3(0.0); ///< Position in space, in KM\n    nString name; ///< Name of the entity\n};\ntypedef vecs::ComponentTable<NamePositionComponent> NamePositionComponentTable;\nKEG_TYPE_DECL(NamePositionComponent);\n\nstruct SpaceLightComponent {\n    vecs::ComponentID npID; ///< Component ID of parent NamePosition component\n    color3 color; ///< Color of the light\n    f32 intensity; ///< Intensity of the light\n};\ntypedef vecs::ComponentTable<SpaceLightComponent> SpaceLightComponentTable;\nKEG_TYPE_DECL(SpaceLightComponent);\n\nstruct OrbitComponent {\n    f64 a = 0.0; ///< Semi-major of the ellipse in KM\n    f64 b = 0.0; ///< Semi-minor of the ellipse in KM\n    f64 t = 0.0; ///< Period of a full orbit in sec\n    f64 parentMass = 0.0; ///< Mass of the parent in KG\n    f64 startMeanAnomaly = 0.0; ///< Start mean anomaly in rad\n    f64 e = 0.0; ///< Shape of orbit, 0-1\n    f64 o = 0.0; ///< Longitude of the ascending node in rad\n    f64 p = 0.0; ///< Longitude of the periapsis in rad\n    f64 i = 0.0; ///< Inclination in rad\n    f64v3 velocity = f64v3(0.0); ///< Current velocity relative to space in KM/s\n    f64v3 relativeVelocity = f64v3(0.0); ///< Current velocity relative to parent in KM/s\n    f32v4 pathColor[2]; ///< Color of the path\n    vecs::ComponentID npID = 0; ///< Component ID of NamePosition component\n    vecs::ComponentID parentOrbId = 0; ///< Component ID of parent OrbitComponent\n    VGBuffer vbo = 0; ///< vbo for the ellipse mesh\n    VGBuffer vao = 0; ///< vao for the ellipse mesh\n    ui32 numVerts = 0; ///< Number of vertices in the ellipse\n    struct Vertex {\n        f32v3 position;\n        f32 angle;\n    };\n    std::vector<Vertex> verts; ///< Vertices for the ellipse\n    f32 currentMeanAnomaly;\n    SpaceObjectType type; ///< Type of object\n    bool isCalculated = false; ///< True when orbit has been calculated\n};\nKEG_TYPE_DECL(OrbitComponent);\n\nstruct PlanetRing {\n    f32 innerRadius;\n    f32 outerRadius;\n    f64q orientation;\n    vio::Path texturePath;\n};\n\nstruct PlanetRingsComponent {\n    vecs::ComponentID namePositionComponent;\n    std::vector<PlanetRing> rings;\n};\ntypedef vecs::ComponentTable<PlanetRingsComponent> PlanetRingsComponentTable;\nKEG_TYPE_DECL(PlanetRingsComponent);\n\nstruct SphericalGravityComponent {\n    vecs::ComponentID namePositionComponent; ///< Component ID of parent NamePosition component\n    f64 radius = 0.0; ///< Radius in KM\n    f64 mass = 0.0; ///< Mass in KG\n};\ntypedef vecs::ComponentTable<SphericalGravityComponent> SphericalGravityComponentTable;\nKEG_TYPE_DECL(SphericalGravityComponent);\n\nstruct SphericalVoxelComponent {\n    ChunkGrid* chunkGrids = nullptr; // should be size 6, one for each face\n    ChunkIOManager* chunkIo = nullptr;\n\n    SphericalHeightmapGenerator* generator = nullptr;\n\n    PlanetGenData* planetGenData = nullptr;\n    const TerrainPatchData* sphericalTerrainData = nullptr;\n\n    const vio::IOManager* saveFileIom = nullptr;\n    const BlockPack* blockPack = nullptr;\n\n    vecs::ComponentID sphericalTerrainComponent = 0;\n    vecs::ComponentID farTerrainComponent = 0;\n    vecs::ComponentID namePositionComponent = 0;\n    vecs::ComponentID axisRotationComponent = 0;\n\n    /// The threadpool for generating chunks and meshes\n    vcore::ThreadPool<WorkerData>* threadPool = nullptr;\n\n    int numCaTasks = 0; /// TODO(Ben): Explore alternative\n\n    f64 voxelRadius = 0; ///< Radius of the planet in voxels\n    int refCount = 1;\n    ui32 updateCount = 0;\n};\nKEG_TYPE_DECL(SphericalVoxelComponent);\n\nstruct SphericalTerrainComponent {\n    vecs::ComponentID namePositionComponent = 0;\n    vecs::ComponentID axisRotationComponent = 0;\n    vecs::ComponentID sphericalVoxelComponent = 0;\n    vecs::ComponentID farTerrainComponent = 0;\n\n    TerrainPatch* patches = nullptr; ///< Buffer for top level patches\n    TerrainPatchData* sphericalTerrainData = nullptr;\n\n    TerrainPatchMeshManager* meshManager = nullptr;\n    SphericalHeightmapGenerator* cpuGenerator = nullptr;\n\n    PlanetGenData* planetGenData = nullptr;\n    VoxelPosition3D startVoxelPosition;\n    bool needsVoxelComponent = false;\n    WorldCubeFace transitionFace = FACE_NONE;\n    f32 alpha = 0.0f; ///< Alpha blending coefficient\n    f32 faceTransTime = START_FACE_TRANS; ///< For animation on fade\n    f64 distance = FLT_MAX;\n    f64 radius = 0.0;\n    bool isFaceTransitioning = false;\n    volatile bool needsFaceTransitionAnimation = false;\n};\nKEG_TYPE_DECL(SphericalTerrainComponent);\n\n\nstruct GasGiantComponent {\n    vecs::ComponentID namePositionComponent = 0;\n    vecs::ComponentID axisRotationComponent = 0;\n    f64 radius = 0.0;\n    f32 oblateness = 1.0f;\n    nString colorMapPath = \"\";\n    Array<PlanetRingProperties> rings;\n};\ntypedef vecs::ComponentTable<GasGiantComponent> GasGiantComponentTable;\nKEG_TYPE_DECL(GasGiantComponent);\n\nstruct StarComponent {\n    vecs::ComponentID namePositionComponent = 0;\n    vecs::ComponentID axisRotationComponent = 0;\n    f64 mass = 0.0; ///< In KG\n    f64 radius = 0.0; ///< In KM\n    f64 temperature = 0.0; ///< In kelvin\n    VGQuery occlusionQuery[2]; ///< TODO(Ben): Delete this\n    f32 visibility = 1.0;\n};\ntypedef vecs::ComponentTable<StarComponent> StarComponentTable;\nKEG_TYPE_DECL(StarComponent);\n\nstruct FarTerrainComponent {\n    TerrainRpcDispatcher* rpcDispatcher = nullptr;\n\n    FarTerrainPatch* patches = nullptr; ///< Buffer for top level patches\n    TerrainPatchData* sphericalTerrainData = nullptr;\n\n    TerrainPatchMeshManager* meshManager = nullptr;\n    SphericalHeightmapGenerator* cpuGenerator = nullptr;\n    vcore::ThreadPool<WorkerData>* threadPool = nullptr;\n\n    WorldCubeFace face = FACE_NONE;\n\n    PlanetGenData* planetGenData = nullptr;\n    i32v2 center = i32v2(0); ///< Center, in units of patch width, where camera is\n    i32v2 origin = i32v2(0); ///< Specifies which patch is the origin (back left corner) on the grid\n    WorldCubeFace transitionFace = FACE_NONE;\n    f32 alpha = 1.0f; ///< Alpha blending coefficient\n    bool shouldFade = false; ///< When this is true we fade out\n};\nKEG_TYPE_DECL(FarTerrainComponent);\n\n#endif // SpaceSystemComponents_h__\n"
  },
  {
    "path": "SoA/SpaceSystemLoadStructs.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SpaceSystemLoadStructs.h\"\n\nKEG_ENUM_DEF(SpaceBodyType, SpaceBodyType, kt) {\n    kt.addValue(\"planet\", SpaceBodyType::PLANET);\n    kt.addValue(\"star\", SpaceBodyType::STAR);\n    kt.addValue(\"gasGiant\", SpaceBodyType::GAS_GIANT);\n}\n\nKEG_ENUM_DEF(SpaceObjectType, SpaceObjectType, kt) {\n    kt.addValue(\"Barycenter\", SpaceObjectType::BARYCENTER);\n    kt.addValue(\"Star\", SpaceObjectType::STAR);\n    kt.addValue(\"Planet\", SpaceObjectType::PLANET);\n    kt.addValue(\"DwarfPlanet\", SpaceObjectType::DWARF_PLANET);\n    kt.addValue(\"Moon\", SpaceObjectType::MOON);\n    kt.addValue(\"DwarfMoon\", SpaceObjectType::DWARF_MOON);\n    kt.addValue(\"Asteroid\", SpaceObjectType::ASTEROID);\n    kt.addValue(\"Comet\", SpaceObjectType::COMET);\n}\n\nstd::string spaceObjectTypeName(const SpaceObjectType &type)\n{\n    static std::unordered_map<SpaceObjectType, std::string> SpaceObjectTypeNames=\n    {\n        {SpaceObjectType::NONE, \"none\"},\n        {SpaceObjectType::BARYCENTER, \"barycenter\"},\n        {SpaceObjectType::STAR, \"star\"},\n        {SpaceObjectType::PLANET, \"planet\"},\n        {SpaceObjectType::DWARF_PLANET, \"dwarfplanet\"},\n        {SpaceObjectType::MOON, \"moon\"},\n        {SpaceObjectType::DWARF_MOON, \"dwarfmoon\"},\n        {SpaceObjectType::ASTEROID, \"asteroid\"},\n        {SpaceObjectType::COMET, \"comet\"}\n    };\n\n    return SpaceObjectTypeNames[type];\n}\n\nKEG_ENUM_DEF(TrojanType, TrojanType, kt) {\n    kt.addValue(\"L4\", TrojanType::L4);\n    kt.addValue(\"L5\", TrojanType::L5);\n}\n\nKEG_TYPE_DEF_SAME_NAME(SystemOrbitProperties, kt) {\n    kt.addValue(\"type\", keg::Value::custom(offsetof(SystemOrbitProperties, type), \"SpaceObjectType\", true));\n    kt.addValue(\"trojan\", keg::Value::custom(offsetof(SystemOrbitProperties, trojan), \"TrojanType\", true));\n    kt.addValue(\"comps\", keg::Value::array(offsetof(SystemOrbitProperties, comps), keg::BasicType::C_STRING));\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, par, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, path, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, ref, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, e, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, t, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, a, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, n, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, p, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, i, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, RA, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, dec, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, dist, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, td, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, SystemOrbitProperties, tf, F64);\n}\n\nKEG_TYPE_DEF_SAME_NAME(AtmosphereProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, AtmosphereProperties, kr, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, AtmosphereProperties, km, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, AtmosphereProperties, g, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, AtmosphereProperties, scaleDepth, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, AtmosphereProperties, waveLength, F32_V3);\n}\n\nKEG_TYPE_DEF_SAME_NAME(PlanetRingProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetRingProperties, innerRadius, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetRingProperties, outerRadius, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetRingProperties, aTilt, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetRingProperties, lNorth, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetRingProperties, colorLookup, STRING);\n}\n\nKEG_TYPE_DEF_SAME_NAME(CloudsProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, CloudsProperties, color, F32_V3);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, CloudsProperties, scale, F32_V3);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, CloudsProperties, density, F32);\n}\n\nKEG_TYPE_DEF_SAME_NAME(PlanetProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetProperties, diameter, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetProperties, density, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetProperties, mass, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetProperties, aTilt, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetProperties, lNorth, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetProperties, rotationalPeriod, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetProperties, displayName, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PlanetProperties, generation, STRING);\n    kt.addValue(\"atmosphere\", keg::Value::custom(offsetof(PlanetProperties, atmosphere), \"AtmosphereKegProperties\", false));\n    kt.addValue(\"clouds\", keg::Value::custom(offsetof(PlanetProperties, clouds), \"CloudsKegProperties\", false));\n}\n\nKEG_TYPE_DEF_SAME_NAME(StarProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, StarProperties, surfaceTemperature, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, StarProperties, diameter, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, StarProperties, density, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, StarProperties, mass, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, StarProperties, aTilt, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, StarProperties, lNorth, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, StarProperties, rotationalPeriod, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, StarProperties, displayName, STRING);\n}\n\nKEG_TYPE_DEF_SAME_NAME(GasGiantProperties, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, diameter, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, density, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, mass, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, aTilt, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, lNorth, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, rotationalPeriod, F64);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, oblateness, F32);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, colorMap, STRING);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, GasGiantProperties, displayName, STRING);\n    kt.addValue(\"atmosphere\", keg::Value::custom(offsetof(GasGiantProperties, atmosphere), \"AtmosphereKegProperties\", false));\n    kt.addValue(\"rings\", keg::Value::array(offsetof(GasGiantProperties, rings), keg::Value::custom(0, \"PlanetRingProperties\", false)));\n}\n"
  },
  {
    "path": "SoA/SpaceSystemLoadStructs.h",
    "content": "///\n/// SpaceSystemLoadStructs.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 20 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Structs for SpaceSystem initialization\n///\n\n#pragma once\n\n#ifndef SpaceSystemLoadStructs_h__\n#define SpaceSystemLoadStructs_h__\n\nstruct PlanetGenData;\n\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/io/Keg.h>\n#include <Vorb/ecs/Entity.h>\n\n#include <unordered_map>\n\nenum class SpaceBodyType {\n    NONE,\n    PLANET,\n    STAR,\n    GAS_GIANT\n};\nKEG_TYPE_DECL(SpaceBodyType);\n\nenum class SpaceObjectType {\n    NONE,\n    BARYCENTER,\n    STAR,\n    PLANET,\n    DWARF_PLANET,\n    MOON,\n    DWARF_MOON,\n    ASTEROID,\n    COMET\n};\nKEG_TYPE_DECL(SpaceObjectType);\n\nstd::string spaceObjectTypeName(const SpaceObjectType &type);\n\nenum class TrojanType {\n    NONE,\n    L4,\n    L5\n};\nKEG_TYPE_DECL(TrojanType);\n\nstruct AtmosphereProperties {\n    f32 kr = 0.0025f;\n    f32 km = 0.0020f;\n    f32 g = -0.99f;\n    f32 scaleDepth = 0.25f;\n    f32v3 waveLength = f32v3(0.65, 0.57, 0.475);\n};\nKEG_TYPE_DECL(AtmosphereProperties);\n\nstruct PlanetRingProperties {\n    f32 innerRadius = 0.0f;\n    f32 outerRadius = 0.0f;\n    f32 aTilt = 0.0f;\n    f32 lNorth = 0.0f;\n    nString colorLookup = \"\";\n};\nKEG_TYPE_DECL(PlanetRingProperties);\n\nstruct CloudsProperties {\n    f32v3 color = f32v3(1.0f, 1.0f, 1.0f);\n    f32v3 scale = f32v3(1.0f, 1.5f, 1.0f);\n    float density = 0.0f;\n};\nKEG_TYPE_DECL(CloudsProperties);\n\nstruct SystemOrbitProperties {\n    SpaceObjectType type = SpaceObjectType::NONE;\n    TrojanType trojan = TrojanType::NONE;\n    Array<const char*> comps;\n    nString par = \"\"; ///< Parent name\n    nString path = \"\"; ///< Path to properties\n    nString ref = \"\"; ///< Orbital period reference body\n    f64 e = 0.0; ///< Shape of orbit, 0-1\n    f64 t = 0.0; ///< Period of a full orbit in sec\n    f64 a = 0.0; ///< Start mean anomaly in deg\n    f64 n = 0.0; ///< Longitude of the ascending node in deg\n    f64 p = 0.0; ///< Longitude of the periapsis in deg\n    f64 i = 0.0; ///< Inclination in deg\n    f64 RA = 0.0; ///< Right ascension relative to sol\n    f64 dec = 0.0; ///< Declination relative to sol\n    f64 dist = 0.0; ///< Distance from sol\n    f64 td = 1.0; ///< Reference body period divisor\n    f64 tf = 1.0; ///< Reference body period factor\n};\nKEG_TYPE_DECL(SystemOrbitProperties);\n\nstruct SystemBody {\n    nString name = \"\";\n    nString parentName = \"\";\n    SystemBody* parent = nullptr;\n    std::vector<SystemBody*> children;\n    vecs::EntityID entity = 0;\n    SpaceBodyType type = SpaceBodyType::NONE;\n    SystemOrbitProperties properties;\n    f64 mass = 0.0;\n    bool isBaryCalculated = false; ///< Used by barycenters\n    bool hasComputedRef = false; ///< True when it has computed trojan and t with ref body\n};\n\nstruct PlanetProperties {\n    f64 diameter = 0.0;\n    f64 density = 0.0;\n    f64 mass = 0.0;\n    f32 aTilt = 0.0;\n    f32 lNorth = 0.0;\n    f64 rotationalPeriod = 0.0;\n    nString displayName = \"\";\n    nString generation = \"\";\n    PlanetGenData* planetGenData = nullptr;\n    AtmosphereProperties atmosphere;\n    CloudsProperties clouds;\n};\nKEG_TYPE_DECL(PlanetProperties);\n\nstruct StarProperties {\n    f64 surfaceTemperature = 0.0; ///< temperature in kelvin\n    f64 diameter = 0.0;\n    f64 density = 0.0;\n    f64 mass = 0.0;\n    f32 aTilt = 0.0;\n    f32 lNorth = 0.0;\n    f64 rotationalPeriod = 0.0;\n    nString displayName = \"\";\n};\nKEG_TYPE_DECL(StarProperties);\n\nstruct GasGiantProperties {\n    f64 diameter = 0.0;\n    f64 density = 0.0;\n    f64 mass = 0.0;\n    f32 aTilt = 0.0;\n    f32 lNorth = 0.0;\n    f64 rotationalPeriod = 0.0;\n    f32 oblateness = 0.0;\n    nString colorMap = \"\";\n    nString displayName = \"\";\n    AtmosphereProperties atmosphere;\n    Array<PlanetRingProperties> rings;\n};\nKEG_TYPE_DECL(GasGiantProperties);\n\n#endif // SpaceSystemLoadStructs_h__\n"
  },
  {
    "path": "SoA/SpaceSystemLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SpaceSystemLoader.h\"\n\n#include \"Constants.h\"\n#include \"Errors.h\"\n#include \"SoaOptions.h\"\n#include \"OrbitComponentUpdater.h\"\n#include \"PlanetGenData.h\"\n#include \"PlanetGenLoader.h\"\n#include \"ProgramGenDelegate.h\"\n#include \"SoAState.h\"\n#include \"SpaceSystemAssemblages.h\"\n#include \"SpaceSystemLoadStructs.h\"\n\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/graphics/Texture.h>\n#include <Vorb/io/Keg.h>\n#include <Vorb/ui/GameWindow.h>\n\nvoid SpaceSystemLoader::init(const SoaState* soaState) {\n    m_soaState = soaState;\n    m_spaceSystem = soaState->spaceSystem;\n    m_ioManager = soaState->systemIoManager;\n    m_threadpool = soaState->threadPool;\n    m_bodyLoader.init(m_ioManager);\n}\n\nvoid SpaceSystemLoader::loadStarSystem(const nString& path) {\n    m_ioManager->setSearchDirectory((path + \"/\").c_str());\n\n    // Load the path color scheme\n    loadPathColors();\n\n    // Load the system\n    loadSystemProperties();\n\n    // Set up binary masses\n    initBinaries();\n\n    // Set up parent connections and orbits\n    initOrbits();\n}\n\n// Only used in SoaEngine::loadPathColors\nstruct PathColorKegProps {\n    ui8v4 base = ui8v4(0);\n    ui8v4 hover = ui8v4(0);\n};\nKEG_TYPE_DEF_SAME_NAME(PathColorKegProps, kt) {\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PathColorKegProps, base, UI8_V4);\n    KEG_TYPE_INIT_ADD_MEMBER(kt, PathColorKegProps, hover, UI8_V4);\n}\n\nbool SpaceSystemLoader::loadPathColors() {\n    nString data;\n    if (!m_ioManager->readFileToString(\"PathColors.yml\", data)) {\n        pError(\"Couldn't find \" + m_ioManager->getSearchDirectory().getString() + \"/PathColors.yml\");\n    }\n\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        fprintf(stderr, \"Failed to load %s\\n\", (m_ioManager->getSearchDirectory().getString() + \"/PathColors.yml\").c_str());\n        context.reader.dispose();\n        return false;\n    }\n\n    bool goodParse = true;\n    auto f = makeFunctor([&](Sender, const nString& name, keg::Node value) {\n        PathColorKegProps props;\n        keg::Error err = keg::parse((ui8*)&props, value, context, &KEG_GLOBAL_TYPE(PathColorKegProps));\n        if (err != keg::Error::NONE) {\n            fprintf(stderr, \"Failed to parse node %s in PathColors.yml\\n\", name.c_str());\n            goodParse = false;\n        }\n        f32v4 base = f32v4(props.base) / 255.0f;\n        f32v4 hover = f32v4(props.hover) / 255.0f;\n        m_spaceSystem->pathColorMap[name] = std::make_pair(base, hover);\n    });\n\n    context.reader.forAllInMap(node, &f);\n    context.reader.dispose();\n    return goodParse;\n}\n\nbool SpaceSystemLoader::loadSystemProperties() {\n    nString data;\n    if (!m_ioManager->readFileToString(\"SystemProperties.yml\", data)) {\n        pError(\"Couldn't find \" + m_ioManager->getSearchDirectory().getString() + \"/SystemProperties.yml\");\n    }\n\n    keg::ReadContext context;\n    context.env = keg::getGlobalEnvironment();\n    context.reader.init(data.c_str());\n    keg::Node node = context.reader.getFirst();\n    if (keg::getType(node) != keg::NodeType::MAP) {\n        fprintf(stderr, \"Failed to load %s\\n\", (m_ioManager->getSearchDirectory().getString() + \"/SystemProperties.yml\").c_str());\n        context.reader.dispose();\n        return false;\n    }\n\n    bool goodParse = true;\n    auto f = makeFunctor([this, &goodParse, &context](Sender, const nString& name, keg::Node value) {\n        // Parse based on the name\n        if (name == \"description\") {\n            m_spaceSystem->systemDescription = keg::convert<nString>(value);\n        } else if (name == \"age\") {\n            m_spaceSystem->age = keg::convert<f32>(value);\n        } else {\n            SystemOrbitProperties properties;\n            keg::Error err = keg::parse((ui8*)&properties, value, context, &KEG_GLOBAL_TYPE(SystemOrbitProperties));\n            if (err != keg::Error::NONE) {\n                fprintf(stderr, \"Failed to parse node %s in SystemProperties.yml\\n\", name.c_str());\n                goodParse = false;\n            }\n\n            // Allocate the body\n            SystemBody* body = new SystemBody;\n            body->name = name;\n            body->parentName = properties.par;\n            body->properties = properties;\n            if (properties.path.size()) {\n                m_bodyLoader.loadBody(m_soaState, properties.path, &properties, body, value);\n                m_bodyLookupMap[body->name] = body->entity;\n            } else {\n                // Make default orbit (used for barycenters)\n                SpaceSystemAssemblages::createOrbit(m_spaceSystem, &properties, body, 0.0);\n            }\n            if (properties.type == SpaceObjectType::BARYCENTER) {\n                m_barycenters[name] = body;\n            }\n            m_systemBodies[name] = body;\n        }\n    });\n    context.reader.forAllInMap(node, &f);\n    context.reader.dispose();\n    return goodParse;\n}\n\nvoid SpaceSystemLoader::initBinaries() {\n    for (auto& it : m_barycenters) {\n        SystemBody* bary = it.second;\n\n        initBinary(bary);\n    }\n}\n\nvoid SpaceSystemLoader::initBinary(SystemBody* bary) {\n    // Don't update twice\n    if (bary->isBaryCalculated) return;\n    bary->isBaryCalculated = true;\n\n    // Need two components or its not a binary\n    if (bary->properties.comps.size() != 2) return;\n\n    // A component\n    auto bodyA = m_systemBodies.find(std::string(bary->properties.comps[0]));\n    if (bodyA == m_systemBodies.end()) return;\n    auto& aProps = bodyA->second->properties;\n\n    // B component\n    auto bodyB = m_systemBodies.find(std::string(bary->properties.comps[1]));\n    if (bodyB == m_systemBodies.end()) return;\n    auto& bProps = bodyB->second->properties;\n\n    { // Set orbit parameters relative to A component\n        bProps.ref = bodyA->second->name;\n        bProps.td = 1.0f;\n        bProps.tf = 1.0f;\n        bProps.e = aProps.e;\n        bProps.i = aProps.i;\n        bProps.n = aProps.n;\n        bProps.p = aProps.p + 180.0;\n        bProps.a = aProps.a;\n        auto& oCmp = m_spaceSystem->orbit.getFromEntity(bodyB->second->entity);\n        oCmp.e = bProps.e;\n        oCmp.i = bProps.i * DEG_TO_RAD;\n        oCmp.p = bProps.p * DEG_TO_RAD;\n        oCmp.o = bProps.n * DEG_TO_RAD;\n        oCmp.startMeanAnomaly = bProps.a * DEG_TO_RAD;\n    }\n\n    // Get the A mass\n    auto& aSgCmp = m_spaceSystem->sphericalGravity.getFromEntity(bodyA->second->entity);\n    f64 massA = aSgCmp.mass;\n    // Recurse if child is a non-constructed binary\n    if (massA == 0.0) {\n        initBinary(bodyA->second);\n        massA = aSgCmp.mass;\n    }\n\n    // Get the B mass\n    auto& bSgCmp = m_spaceSystem->sphericalGravity.getFromEntity(bodyB->second->entity);\n    f64 massB = bSgCmp.mass;\n    // Recurse if child is a non-constructed binary\n    if (massB == 0.0) {\n        initBinary(bodyB->second);\n        massB = bSgCmp.mass;\n    }\n\n    // Set the barycenter mass\n    bary->mass = massA + massB;\n\n    auto& barySgCmp = m_spaceSystem->sphericalGravity.getFromEntity(bary->entity);\n    barySgCmp.mass = bary->mass;\n\n    { // Calculate A orbit\n        SystemBody* body = bodyA->second;\n        body->parent = bary;\n        bary->children.push_back(body);\n        f64 massRatio = massB / (massA + massB);\n        calculateOrbit(body->entity,\n                       barySgCmp.mass,\n                       body, massRatio);\n    }\n\n    { // Calculate B orbit\n        SystemBody* body = bodyB->second;\n        body->parent = bary;\n        bary->children.push_back(body);\n        f64 massRatio = massA / (massA + massB);\n        calculateOrbit(body->entity,\n                       barySgCmp.mass,\n                       body, massRatio);\n    }\n\n    { // Set orbit colors from A component\n        auto& oCmp = m_spaceSystem->orbit.getFromEntity(bodyA->second->entity);\n        auto& baryOCmp = m_spaceSystem->orbit.getFromEntity(bary->entity);\n        baryOCmp.pathColor[0] = oCmp.pathColor[0];\n        baryOCmp.pathColor[1] = oCmp.pathColor[1];\n    }\n}\n\nvoid recursiveInclinationCalc(OrbitComponentTable& ct, SystemBody* body, f64 inclination) {\n    for (auto& c : body->children) {\n        OrbitComponent& orbitC = ct.getFromEntity(c->entity);\n        orbitC.i += inclination;\n        recursiveInclinationCalc(ct, c, orbitC.i);\n    }\n}\n\nvoid SpaceSystemLoader::initOrbits() {\n    // Set parent connections\n    for (auto& it : m_systemBodies) {\n        SystemBody* body = it.second;\n        const nString& parent = body->parentName;\n        if (parent.length()) {\n            // Check for parent\n            auto p = m_systemBodies.find(parent);\n            if (p != m_systemBodies.end()) {\n                // Set up parent connection\n                body->parent = p->second;\n                p->second->children.push_back(body);\n            }\n        }\n    }\n\n    // Child propagation for inclination\n    // TODO(Ben): Do this right\n    /* for (auto& it : pr.systemBodies) {\n    SystemBody* body = it.second;\n    if (!body->parent) {\n    recursiveInclinationCalc(pr.spaceSystem->m_orbitCT, body,\n    pr.spaceSystem->m_orbitCT.getFromEntity(body->entity).i);\n    }\n    }*/\n\n    // Finally, calculate the orbits\n    for (auto& it : m_systemBodies) {\n        SystemBody* body = it.second;\n        // Calculate the orbit using parent mass\n        if (body->parent) {\n            calculateOrbit(body->entity,\n                           m_spaceSystem->sphericalGravity.getFromEntity(body->parent->entity).mass,\n                           body);\n        }\n    }\n}\n\nvoid SpaceSystemLoader::computeRef(SystemBody* body) {\n    if (!body->properties.ref.empty()) {\n        OrbitComponent& orbitC = m_spaceSystem->orbit.getFromEntity(body->entity);\n        // Find reference body\n        auto it = m_systemBodies.find(body->properties.ref);\n        if (it != m_systemBodies.end()) {\n            SystemBody* ref = it->second;\n            // Recursively compute ref if needed\n            if (!ref->hasComputedRef) computeRef(ref);\n            // Calculate period using reference body\n            orbitC.t = ref->properties.t * body->properties.tf / body->properties.td;\n            body->properties.t = orbitC.t;\n            // Handle trojans\n            if (body->properties.trojan == TrojanType::L4) {\n                body->properties.a = ref->properties.a + 60.0f;\n                orbitC.startMeanAnomaly = body->properties.a * DEG_TO_RAD;\n            } else if (body->properties.trojan == TrojanType::L5) {\n                body->properties.a = ref->properties.a - 60.0f;\n                orbitC.startMeanAnomaly = body->properties.a * DEG_TO_RAD;\n            }\n        } else {\n            fprintf(stderr, \"Failed to find ref body %s\\n\", body->properties.ref.c_str());\n        }\n    }\n    body->hasComputedRef = true;\n}\n\nvoid SpaceSystemLoader::calculateOrbit(vecs::EntityID entity, f64 parentMass,\n                               SystemBody* body, f64 binaryMassRatio /* = 0.0 */) {\n    OrbitComponent& orbitC = m_spaceSystem->orbit.getFromEntity(entity);\n\n    // If the orbit was already calculated, don't do it again.\n    if (orbitC.isCalculated) return;\n    orbitC.isCalculated = true;\n\n    // Provide the orbit component with it's parent\n    m_spaceSystem->orbit.getFromEntity(body->entity).parentOrbId =\n        m_spaceSystem->orbit.getComponentID(body->parent->entity);\n\n    computeRef(body);\n\n    f64 t = orbitC.t;\n    auto& sgCmp = m_spaceSystem->sphericalGravity.getFromEntity(entity);\n    f64 mass = sgCmp.mass;\n    f64 diameter = sgCmp.radius * 2.0;\n\n    if (binaryMassRatio > 0.0) { // Binary orbit\n        orbitC.a = pow((t * t) * M_G * parentMass /\n                       (4.0 * (M_PI * M_PI)), 1.0 / 3.0) * KM_PER_M * binaryMassRatio;\n    } else { // Regular orbit\n        // Calculate semi-major axis\n        orbitC.a = pow((t * t) * M_G * (mass + parentMass) /\n                       (4.0 * (M_PI * M_PI)), 1.0 / 3.0) * KM_PER_M;\n    }\n\n    // Calculate semi-minor axis\n    orbitC.b = orbitC.a * sqrt(1.0 - orbitC.e * orbitC.e);\n\n    // Set parent pass\n    orbitC.parentMass = parentMass;\n\n    // TODO(Ben): Doesn't work right for binaries due to parentMass\n    { // Check tidal lock\n        f64 ns = log10(0.003 * pow(orbitC.a, 6.0) * pow(diameter + 500.0, 3.0) / (mass * orbitC.parentMass) * (1.0 + (f64)1e20 / (mass + orbitC.parentMass)));\n        if (ns < 0) {\n            // It is tidally locked so lock the rotational period\n            m_spaceSystem->axisRotation.getFromEntity(entity).period = t;\n        }\n    }\n\n    { // Make the ellipse mesh with stepwise simulation\n        OrbitComponentUpdater updater;\n        static const int NUM_VERTS = 2880;\n        orbitC.verts.resize(NUM_VERTS + 1);\n        f64 timePerDeg = orbitC.t / (f64)NUM_VERTS;\n        NamePositionComponent& npCmp = m_spaceSystem->namePosition.get(orbitC.npID);\n        f64v3 startPos = npCmp.position;\n        for (int i = 0; i < NUM_VERTS; i++) {\n\n            if (orbitC.parentOrbId) {\n                OrbitComponent* pOrbC = &m_spaceSystem->orbit.get(orbitC.parentOrbId);\n                updater.updatePosition(orbitC, i * timePerDeg, &npCmp,\n                                       pOrbC,\n                                       &m_spaceSystem->namePosition.get(pOrbC->npID));\n            } else {\n                updater.updatePosition(orbitC, i * timePerDeg, &npCmp);\n            }\n\n            OrbitComponent::Vertex vert;\n            vert.position = npCmp.position;\n            vert.angle = 1.0f - (f32)i / (f32)NUM_VERTS;\n            orbitC.verts[i] = vert;\n        }\n        orbitC.verts.back() = orbitC.verts.front();\n        npCmp.position = startPos;\n    }\n}\n"
  },
  {
    "path": "SoA/SpaceSystemLoader.h",
    "content": "///\n/// SpaceSystemLoader.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 4 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Loads the space system\n///\n\n#pragma once\n\n#ifndef SpaceSystemLoader_h__\n#define SpaceSystemLoader_h__\n\n#include <Vorb/ecs/Entity.h>\n#include <Vorb/VorbPreDecl.inl>\n#include \"VoxPool.h\"\n#include \"SystemBodyLoader.h\"\n\nstruct GasGiantProperties;\nstruct SystemBody;\nstruct SystemOrbitProperties;\nclass SpaceSystem;\nclass PlanetGenLoader;\n\nDECL_VIO(class IOManager)\nDECL_VCORE(class RPCManager)\n\nclass SpaceSystemLoader {\npublic:\n    void init(const SoaState* soaState);\n    /// Loads and adds a star system to the SpaceSystem\n    /// @param pr: params\n    void loadStarSystem(const nString& path);\nprivate:\n    /// Loads path color scheme\n    /// @param pr: params\n    /// @return true on success\n    bool loadPathColors();\n\n    /// Loads and adds system properties to the params\n    /// @param pr: params\n    /// @return true on success\n    bool loadSystemProperties();\n\n    // Sets up mass parameters for binaries\n    void initBinaries();\n    // Recursive function for binary creation\n    void initBinary(SystemBody* bary);\n\n    // Initializes orbits and parent connections\n    void initOrbits();\n\n    void computeRef(SystemBody* body);\n\n    void calculateOrbit(vecs::EntityID entity, f64 parentMass,\n                        SystemBody* body, f64 binaryMassRatio = 0.0);\n\n    SystemBodyLoader m_bodyLoader;\n    \n    const SoaState* m_soaState = nullptr;\n    SpaceSystem* m_spaceSystem;\n    vio::IOManager* m_ioManager = nullptr;\n    vcore::ThreadPool<WorkerData>* m_threadpool = nullptr;\n    std::map<nString, SystemBody*> m_barycenters;\n    std::map<nString, SystemBody*> m_systemBodies;\n    std::map<nString, vecs::EntityID> m_bodyLookupMap;\n};\n\n#endif // SpaceSystemLoader_h__\n"
  },
  {
    "path": "SoA/SpaceSystemRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SpaceSystem.h\"\n#include \"SpaceSystemRenderStage.h\"\n\n#include <Vorb/graphics/DepthState.h>\n#include <Vorb/graphics/RasterizerState.h>\n\n#include \"App.h\"\n#include \"Camera.h\"\n#include \"DebugRenderer.h\"\n#include \"Errors.h\"\n#include \"MTRenderState.h\"\n#include \"MainMenuSystemViewer.h\"\n#include \"RenderUtils.h\"\n#include \"SoAState.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"TerrainPatch.h\"\n#include \"TerrainPatchMeshManager.h\"\n#include \"soaUtils.h\"\n\n#include <Vorb/Timing.h>\n\n#define ATMO_LOAD_DIST 50000.0f\n\n/* ===================== LoadContext =================== */\nconst ui32 LENS_WORK = 2;\nconst ui32 STAR_WORK = 2;\nconst ui32 AR_WORK = 2;\nconst ui32 SPHER_WORK = 2;\nconst ui32 GAS_WORK = 2;\nconst ui32 CLOUD_WORK = 2;\nconst ui32 ATMO_WORK = 2;\nconst ui32 RING_WORK = 2;\nconst ui32 FAR_WORK = 2;\n// Make sure to sum all work here\nconst ui32 TOTAL_WORK = LENS_WORK + STAR_WORK + AR_WORK +\n                        SPHER_WORK + GAS_WORK + CLOUD_WORK +\n                        ATMO_WORK + RING_WORK + FAR_WORK;\n// Make sure NUM_TASKS matches the number of tasks listed\nconst ui32 NUM_TASKS = 9;\n/* ====================================================== */\n\nconst f64q FACE_ORIENTATIONS[6] = {\n    f64q(f64v3(0.0, 0.0, 0.0)), // TOP\n    f64q(f64v3(0.0, 0.0, -M_PI / 2.0)), // LEFT\n    f64q(f64v3(0.0, 0.0, M_PI / 2.0)), // RIGHT\n    f64q(f64v3(M_PI / 2.0, 0.0, 0.0)), // FRONT\n    f64q(f64v3(-M_PI / 2.0, 0.0, 0.0)), // BACK\n    f64q(f64v3(M_PI, 0.0, 0.0))  // BOTTOM\n};\n\nvoid SpaceSystemRenderStage::init(vui::GameWindow* window, StaticLoadContext& context) {\n    IRenderStage::init(window, context);\n    context.addAnticipatedWork(TOTAL_WORK, NUM_TASKS);\n}\n\nvoid SpaceSystemRenderStage::hook(SoaState* state, const Camera* spaceCamera, const Camera* farTerrainCamera /*= nullptr*/) {\n    m_viewport = m_window->getViewportDims();\n    m_spaceSystem = state->spaceSystem;\n    m_mainMenuSystemViewer = state->clientState.systemViewer;\n    m_lensFlareRenderer.init(&state->clientState.texturePathResolver);\n    m_starRenderer.init(&state->clientState.texturePathResolver);\n    m_systemARRenderer.init(&state->clientState.texturePathResolver);\n    m_spaceCamera = spaceCamera;\n    m_farTerrainCamera = farTerrainCamera;\n}\n\nvoid SpaceSystemRenderStage::load(StaticLoadContext& context) {\n    context.addTask([&](Sender, void*) {\n        m_lensFlareRenderer.initGL();\n        context.addWorkCompleted(LENS_WORK);\n    }, false);\n    context.addTask([&](Sender, void*) {\n        m_starRenderer.initGL();\n        context.addWorkCompleted(STAR_WORK);\n    }, false);\n    context.addTask([&](Sender, void*) {\n        m_systemARRenderer.initGL();\n        context.addWorkCompleted(AR_WORK);\n    }, false);\n    context.addTask([&](Sender, void*) {\n        m_sphericalTerrainComponentRenderer.initGL();\n        context.addWorkCompleted(SPHER_WORK);\n    }, false);\n    context.addTask([&](Sender, void*) {\n        m_gasGiantComponentRenderer.initGL();\n        context.addWorkCompleted(GAS_WORK);\n    }, false);\n    context.addTask([&](Sender, void*) {\n        m_cloudsComponentRenderer.initGL();\n        context.addWorkCompleted(CLOUD_WORK);\n    }, false);\n    context.addTask([&](Sender, void*) {\n        m_atmosphereComponentRenderer.initGL();\n        context.addWorkCompleted(ATMO_WORK);\n    }, false);\n    context.addTask([&](Sender, void*) {\n        m_ringsRenderer.initGL();\n        context.addWorkCompleted(RING_WORK);\n    }, false);\n    context.addTask([&](Sender, void*) {\n        m_farTerrainComponentRenderer.initGL();\n        context.addWorkCompleted(LENS_WORK);\n    }, false);\n}\n\nvoid SpaceSystemRenderStage::dispose(StaticLoadContext& context VORB_MAYBE_UNUSED) {\n    m_lensFlareRenderer.dispose();\n    m_starRenderer.dispose();\n    m_systemARRenderer.dispose();\n    m_sphericalTerrainComponentRenderer.dispose();\n    m_gasGiantComponentRenderer.dispose();\n    m_cloudsComponentRenderer.dispose();\n    m_atmosphereComponentRenderer.dispose();\n    m_ringsRenderer.dispose();\n    m_farTerrainComponentRenderer.dispose();\n}\n\nvoid SpaceSystemRenderStage::setRenderState(const MTRenderState* renderState) {\n    m_renderState = renderState;\n}\n\nvoid SpaceSystemRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    drawBodies();\n    if (m_showAR) m_systemARRenderer.draw(m_spaceSystem, m_spaceCamera,\n                                          m_mainMenuSystemViewer,\n                                          m_viewport);\n}\n\nvoid SpaceSystemRenderStage::reloadShaders() {\n    StaticLoadContext tmp;\n    dispose(tmp);\n\n    m_lensFlareRenderer.initGL();\n    m_starRenderer.initGL();\n    m_systemARRenderer.initGL();\n    m_sphericalTerrainComponentRenderer.initGL();\n    m_gasGiantComponentRenderer.initGL();\n    m_cloudsComponentRenderer.initGL();\n    m_atmosphereComponentRenderer.initGL();\n    m_ringsRenderer.initGL();\n    m_farTerrainComponentRenderer.initGL();\n}\n\nvoid SpaceSystemRenderStage::renderStarGlows(const f32v3& colorMult) {\n    for (auto& it : m_starGlowsToRender) {\n        m_starRenderer.drawGlow(it.first, m_spaceCamera->getViewProjectionMatrix(), it.second,\n                                m_spaceCamera->getAspectRatio(), m_spaceCamera->getDirection(),\n                                m_spaceCamera->getRight(), colorMult);\n        // TODO(Ben): Don't do this twice?\n        f32v3 starColor = m_starRenderer.calculateStarColor(it.first);\n        f32 intensity = (f32)glm::min(m_starRenderer.calculateGlowSize(it.first, it.second), 1.0) * it.first.visibility;\n        m_lensFlareRenderer.render(m_spaceCamera->getViewProjectionMatrix(), it.second,\n                                   starColor * colorMult,\n                                   m_spaceCamera->getAspectRatio(), 0.1f, intensity);\n    }\n}\n\nvoid SpaceSystemRenderStage::drawBodies() {\n\n    glEnable(GL_DEPTH_CLAMP);\n    bool needsDepthClear = false;\n    // TODO(Ben): Optimize out getFromEntity\n    f64v3 lightPos;\n    // For caching light for far terrain\n    std::map<vecs::EntityID, std::pair<f64v3, SpaceLightComponent*> > lightCache;\n    const f64v3* pos;\n    f32 zCoef = computeZCoef(m_spaceCamera->getFarClip());\n    // Render spherical terrain\n    for (auto& it : m_spaceSystem->sphericalTerrain) {\n        auto& cmp = it.second;\n        auto& npCmp = m_spaceSystem->namePosition.get(cmp.namePositionComponent);\n        // Cant render if it hasn't generated yet\n        if (!cmp.planetGenData) continue;\n        // Indicate the need for face transition animation\n        if (cmp.needsFaceTransitionAnimation) {\n            cmp.needsFaceTransitionAnimation = false;\n            needsFaceTransitionAnimation = true;\n        }\n\n        // If we are using MTRenderState, get position from it\n        pos = getBodyPosition(npCmp, it.first);\n\n        // Need to clear depth on fade transitions\n        if (cmp.farTerrainComponent && (cmp.alpha > 0.0f && cmp.alpha < TERRAIN_FADE_LENGTH)) {\n            needsDepthClear = true;\n        }\n\n        SpaceLightComponent* lightCmp = getBrightestLight(npCmp, lightPos);\n        lightCache[it.first] = std::make_pair(lightPos, lightCmp);\n\n        f32v3 lightDir(glm::normalize(lightPos - *pos));\n    \n        m_sphericalTerrainComponentRenderer.draw(cmp, m_spaceCamera,\n                                                 lightDir,\n                                                 *pos,\n                                                 zCoef,\n                                                 lightCmp,\n                                                 &m_spaceSystem->axisRotation.get(cmp.axisRotationComponent),\n                                                 &m_spaceSystem->atmosphere.getFromEntity(it.first));\n    }\n    // Render gas giants\n    for (auto& it : m_spaceSystem->gasGiant) {\n        auto& ggCmp = it.second;\n        auto& npCmp = m_spaceSystem->namePosition.get(ggCmp.namePositionComponent);\n\n        pos = getBodyPosition(npCmp, it.first);\n\n        f32v3 relCamPos(m_spaceCamera->getPosition() - *pos);\n\n        SpaceLightComponent* lightCmp = getBrightestLight(npCmp, lightPos);\n        lightCache[it.first] = std::make_pair(lightPos, lightCmp);\n\n        f32v3 lightDir(glm::normalize(lightPos - *pos));\n\n        m_gasGiantComponentRenderer.draw(ggCmp, it.first,\n                                         m_spaceCamera->getViewProjectionMatrix(),\n                                         m_spaceSystem->axisRotation.getFromEntity(it.first).currentOrientation,\n                                         relCamPos, lightDir,\n                                         zCoef, lightCmp,\n                                         &m_spaceSystem->atmosphere.getFromEntity(it.first));\n    }\n\n    // Render clouds\n  /*  glDisable(GL_CULL_FACE);\n    for (auto& it : m_spaceSystem->m_cloudsCT) {\n        auto& cCmp = it.second;\n        auto& npCmp = m_spaceSystem->m_namePositionCT.get(cCmp.namePositionComponent);\n\n        pos = getBodyPosition(npCmp, it.first);\n        f32v3 relCamPos(m_spaceCamera->getPosition() - *pos);\n        auto& l = lightCache[it.first];\n        f32v3 lightDir(glm::normalize(l.first - *pos));\n        \n        m_cloudsComponentRenderer.draw(cCmp, m_spaceCamera->getViewProjectionMatrix(), relCamPos, lightDir,\n                                       zCoef, l.second,\n                                       m_spaceSystem->m_axisRotationCT.getFromEntity(it.first), \n                                       m_spaceSystem->m_atmosphereCT.getFromEntity(it.first));\n    }\n    glEnable(GL_CULL_FACE);*/\n\n    // Render atmospheres\n    for (auto& it : m_spaceSystem->atmosphere) {\n        auto& atCmp = it.second;\n        auto& npCmp = m_spaceSystem->namePosition.get(atCmp.namePositionComponent);\n\n        pos = getBodyPosition(npCmp, it.first);\n\n        f32v3 relCamPos(m_spaceCamera->getPosition() - *pos);\n\n        if (glm::length(relCamPos) < atCmp.radius * 11.0f) {\n            auto& l = lightCache[it.first];\n\n            f32v3 lightDir(glm::normalize(l.first - *pos));\n\n            m_atmosphereComponentRenderer.draw(atCmp, m_spaceCamera->getViewProjectionMatrix(), relCamPos, lightDir,\n                                               zCoef, l.second);\n        }\n    }\n\n    // Render planet rings\n    glDepthMask(GL_FALSE);\n    for (auto& it : m_spaceSystem->planetRings) {\n        auto& prCmp = it.second;\n        auto& npCmp = m_spaceSystem->namePosition.get(prCmp.namePositionComponent);\n\n        // TODO(Ben): Don't use getFromEntity\n        auto& sgCmp = m_spaceSystem->sphericalGravity.getFromEntity(it.first);\n\n        pos = getBodyPosition(npCmp, it.first);\n\n        f32v3 relCamPos(m_spaceCamera->getPosition() - *pos);\n\n        auto& l = lightCache[it.first];\n\n        f32v3 lightDir(glm::normalize(l.first - *pos));\n\n        // TODO(Ben): Worry about f64 to f32 precision loss\n        m_ringsRenderer.draw(prCmp, it.first, m_spaceCamera->getViewProjectionMatrix(), relCamPos,\n                             f32v3(l.first - m_spaceCamera->getPosition()), (f32)sgCmp.radius,\n                             zCoef, l.second);\n    }\n    glDepthMask(GL_TRUE);\n\n    // Render far terrain\n    if (m_farTerrainCamera) {\n\n        if (needsDepthClear) {\n            glClear(GL_DEPTH_BUFFER_BIT);\n        }\n\n        for (auto& it : m_spaceSystem->farTerrain) {\n            auto& cmp = it.second;\n            auto& npCmp = m_spaceSystem->namePosition.getFromEntity(it.first);\n\n            if (!cmp.meshManager) continue;\n\n            pos = getBodyPosition(npCmp, it.first);\n\n            auto& l = lightCache[it.first];\n            f64v3 lightDir = glm::normalize(l.first - *pos);\n\n            m_farTerrainComponentRenderer.draw(cmp, m_farTerrainCamera,\n                                               lightDir,\n                                               zCoef,\n                                               l.second,\n                                               &m_spaceSystem->axisRotation.getFromEntity(it.first),\n                                               &m_spaceSystem->atmosphere.getFromEntity(it.first));\n        }\n    }\n\n    // Render stars\n    m_starGlowsToRender.clear();\n    for (auto& it : m_spaceSystem->star) {\n        auto& sCmp = it.second;\n        auto& npCmp = m_spaceSystem->namePosition.get(sCmp.namePositionComponent);\n\n        pos = getBodyPosition(npCmp, it.first);\n\n        f64v3 relCamPos = m_spaceCamera->getPosition() - *pos;\n        f32v3 fRelCamPos(relCamPos);\n\n        // Render the star\n        m_starRenderer.updateOcclusionQuery(sCmp, zCoef, m_spaceCamera->getViewProjectionMatrix(), relCamPos);\n        m_starRenderer.drawStar(sCmp, m_spaceCamera->getViewProjectionMatrix(), f64q(), fRelCamPos, zCoef);\n        m_starRenderer.drawCorona(sCmp, m_spaceCamera->getViewProjectionMatrix(), m_spaceCamera->getViewMatrix(), fRelCamPos, zCoef);\n        \n        m_starGlowsToRender.emplace_back(sCmp, relCamPos);\n    }\n\n    glDisable(GL_DEPTH_CLAMP);\n    vg::DepthState::FULL.set();\n}\n\nSpaceLightComponent* SpaceSystemRenderStage::getBrightestLight(NamePositionComponent& npCmp, OUT f64v3& pos) {\n    SpaceLightComponent* rv = nullptr;\n    f64 closestDist = 999999999999999999999999999999999999999999999.0;\n    for (auto& it : m_spaceSystem->spaceLight) {\n        auto& lightNpCmp = m_spaceSystem->namePosition.get(it.second.npID);    \n        f64 dist = selfDot(lightNpCmp.position - npCmp.position);\n        if (dist < closestDist) {\n            closestDist = dist;\n            rv = &it.second;\n            pos = lightNpCmp.position;\n        }\n    }\n    return rv;\n}\n\nconst f64v3* SpaceSystemRenderStage::getBodyPosition(NamePositionComponent& npCmp, vecs::EntityID eid) {\n    const f64v3* pos;\n    // If we are using MTRenderState, get position from it\n    if (m_renderState) {\n        auto sit = m_renderState->spaceBodyPositions.find(eid);\n        if (sit != m_renderState->spaceBodyPositions.end()) {\n            pos = &sit->second;\n        } else {\n            pos = &npCmp.position;\n        }\n    } else {\n        pos = &npCmp.position;\n    }\n    return pos;\n}\n"
  },
  {
    "path": "SoA/SpaceSystemRenderStage.h",
    "content": "///\n/// SpaceSystemRenderStage.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 5 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Render stage for drawing the space system\n///\n\n#pragma once\n\n#ifndef SpaceSystemRenderStage_h__\n#define SpaceSystemRenderStage_h__\n\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/AssetLoader.h>\n\n#include \"CloudsComponentRenderer.h\"\n#include \"AtmosphereComponentRenderer.h\"\n#include \"Camera.h\"\n#include \"FarTerrainComponentRenderer.h\"\n#include \"GasGiantComponentRenderer.h\"\n#include \"LenseFlareRenderer.h\"\n#include \"PlanetRingsComponentRenderer.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"SphericalTerrainComponentRenderer.h\"\n#include \"StarComponentRenderer.h\"\n#include \"SystemARRenderer.h\"\n#include \"IRenderStage.h\"\n\nclass App;\nclass GameSystem;\nclass MainMenuSystemViewer;\nstruct SoaState;\nclass SpaceSystem;\nclass SpriteBatch;\nclass SpriteFont;\nstruct MTRenderState;\n\nclass SpaceSystemRenderStage : public IRenderStage {\npublic:\n    void init(vui::GameWindow* window, StaticLoadContext& context) override;\n\n    void hook(SoaState* state, const Camera* spaceCamera, const Camera* farTerrainCamera = nullptr);\n\n    void load(StaticLoadContext& context) override;\n\n    void dispose(StaticLoadContext& context) override;\n\n    //TODO(Ben): Pointer to window viewport instead?\n    void setViewport(const ui32v2& viewport) { m_viewport = f32v2(viewport); }\n\n    void setFarTerrainCamera(const Camera* camera) { m_farTerrainCamera = camera; }\n\n    /// Call this every frame before render\n    void setRenderState(const MTRenderState* renderState);\n    /// Draws the render stage\n    virtual void render(const Camera* camera) override;\n\n    void reloadShaders();\n\n    /// Renders star glows requested in the render call. Call after HDR\n    void renderStarGlows(const f32v3& colorMult);\n\n    void setSystemViewer(const MainMenuSystemViewer* viewer) { m_mainMenuSystemViewer = viewer; }\n    void setShowAR(bool showAR) { m_showAR = showAR; }\n\n    bool needsFaceTransitionAnimation = false; ///< true when we need to fade out camera for transition between faces\nprivate:\n    /// Renders the space bodies\n    /// @param camera: Camera for rendering\n    /// @param terrainProgram: Program for rendering terrain\n    /// @param waterProgram: Program for rendering water\n    void drawBodies();\n\n    /// Gets light source relative to a component\n    /// @param cmp: position component \n    /// @param pos: Returned position of brightest light\n    /// @return brightest light source relative to cmp\n    SpaceLightComponent* getBrightestLight(NamePositionComponent& npCmp, OUT f64v3& pos);\n\n    /// Gets the position of a body using MTRenderState if needed\n    /// @return pointer to the position\n    const f64v3* getBodyPosition(NamePositionComponent& npCmp, vecs::EntityID eid);\n\n    f32v2 m_viewport;\n    SpaceSystem* m_spaceSystem = nullptr;\n    const MainMenuSystemViewer* m_mainMenuSystemViewer = nullptr;\n    const Camera* m_spaceCamera = nullptr;\n    const Camera* m_farTerrainCamera = nullptr;\n    const MTRenderState* m_renderState = nullptr;\n    \n    CloudsComponentRenderer m_cloudsComponentRenderer;\n    AtmosphereComponentRenderer m_atmosphereComponentRenderer;\n    PlanetRingsComponentRenderer m_ringsRenderer;\n    FarTerrainComponentRenderer m_farTerrainComponentRenderer;\n    GasGiantComponentRenderer m_gasGiantComponentRenderer;\n    LenseFlareRenderer m_lensFlareRenderer;\n    SphericalTerrainComponentRenderer m_sphericalTerrainComponentRenderer;\n    StarComponentRenderer m_starRenderer;\n    SystemARRenderer m_systemARRenderer;\n  \n    std::vector<std::pair<StarComponent, f64v3> > m_starGlowsToRender;\n    bool m_showAR = true;\n\n    vcore::GLRPC m_rpc;\n};\n\n#endif // SpaceSystemRenderStage_h__"
  },
  {
    "path": "SoA/SpaceSystemUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SpaceSystemUpdater.h\"\n\n#include \"SoAState.h\"\n\n#include <Vorb/Timing.h>\n\nvoid SpaceSystemUpdater::init(const SoaState* soaState) {\n    // Set planet rotation\n    m_axisRotationComponentUpdater.update(soaState->spaceSystem, soaState->time);\n    // Set initial position\n    m_orbitComponentUpdater.update(soaState->spaceSystem, soaState->time);\n}\n\nvoid SpaceSystemUpdater::update(SoaState* soaState, const f64v3& spacePos, const f64v3& voxelPos) {\n\n    // Get handles\n    SpaceSystem* spaceSystem = soaState->spaceSystem;\n    // const GameSystem* gameSystem = soaState->gameSystem;\n\n    // Update planet rotation\n    m_axisRotationComponentUpdater.update(spaceSystem, soaState->time);\n\n    // Update far terrain\n    // Update this BEFORE sphericalTerrain\n    m_farTerrainComponentUpdater.update(spaceSystem, voxelPos * KM_PER_VOXEL);\n\n    // Update Spherical Terrain\n    m_sphericalTerrainComponentUpdater.update(soaState, spacePos);\n\n    // Update voxels\n    m_sphericalVoxelComponentUpdater.update(soaState);\n\n    // Update Orbits ( Do this last)\n    m_orbitComponentUpdater.update(spaceSystem, soaState->time);\n}\n\nvoid SpaceSystemUpdater::glUpdate(const SoaState* soaState) {\n    m_sphericalTerrainComponentUpdater.glUpdate(soaState);\n    m_farTerrainComponentUpdater.glUpdate(soaState->spaceSystem);\n}"
  },
  {
    "path": "SoA/SpaceSystemUpdater.h",
    "content": "///\n/// SpaceSystemUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 20 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates the SpaceSystem\n///\n\n#pragma once\n\n#ifndef SpaceSystemUpdater_h__\n#define SpaceSystemUpdater_h__\n\n#include \"AxisRotationComponentUpdater.h\"\n#include \"FarTerrainComponentUpdater.h\"\n#include \"OrbitComponentUpdater.h\"\n#include \"SphericalTerrainComponentUpdater.h\"\n#include \"SphericalVoxelComponentUpdater.h\"\n\nclass SpaceSystem;\nclass GameSystem;\nstruct SoaState;\n\nclass SpaceSystemUpdater {\npublic:\n    void init(const SoaState* soaState);\n    void update(SoaState* soaState, const f64v3& spacePos, const f64v3& voxelPos);\n\n    /// Updates OpenGL specific stuff, should be called on render thread\n    void glUpdate(const SoaState* soaState);\n\nprivate:\n    /// Updaters\n    friend class OrbitComponentUpdater;\n    OrbitComponentUpdater m_orbitComponentUpdater;\n    friend class SphericalVoxelComponentUpdater;\n    SphericalVoxelComponentUpdater m_sphericalVoxelComponentUpdater;\n    friend class SphericalTerrainComponentUpdater;\n    SphericalTerrainComponentUpdater m_sphericalTerrainComponentUpdater;\n    friend class AxisRotationComponentUpdater;\n    AxisRotationComponentUpdater m_axisRotationComponentUpdater;\n    FarTerrainComponentUpdater m_farTerrainComponentUpdater;\n};\n\n#endif // SpaceSystemUpdater_h__\n"
  },
  {
    "path": "SoA/SphericalHeightmapGenerator.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SphericalHeightmapGenerator.h\"\n\n#include \"PlanetHeightData.h\"\n#include \"VoxelSpaceConversions.h\"\n#include \"Noise.h\"\n#include \"soaUtils.h\"\n#include <random>\n\n#define WEIGHT_THRESHOLD 0.001\n\nvoid SphericalHeightmapGenerator::init(const PlanetGenData* planetGenData) {\n    m_genData = planetGenData;\n}\n\nvoid SphericalHeightmapGenerator::generateHeightData(OUT PlanetHeightData& height, const VoxelPosition2D& facePosition) const {\n    // Need to convert to world-space\n    f32v2 coordMults = f32v2(VoxelSpaceConversions::FACE_TO_WORLD_MULTS[(int)facePosition.face]);\n    i32v3 coordMapping = VoxelSpaceConversions::VOXEL_TO_WORLD[(int)facePosition.face];\n\n    f64v3 pos;\n    pos[coordMapping.x] = facePosition.pos.x * KM_PER_VOXEL * coordMults.x;\n    pos[coordMapping.y] = m_genData->radius * (f64)VoxelSpaceConversions::FACE_Y_MULTS[(int)facePosition.face];\n    pos[coordMapping.z] = facePosition.pos.y * KM_PER_VOXEL * coordMults.y;\n\n    f64v3 normal = glm::normalize(pos);\n\n    generateHeightData(height, normal * m_genData->radius, normal);\n\n    // For Voxel Position, automatically get tree or flora\n    height.flora = getTreeID(height.biome, facePosition, pos);\n    // If no tree, try flora\n    if (height.flora == FLORA_ID_NONE) {\n        height.flora = getFloraID(height.biome, facePosition, pos);\n    }\n}\n\nvoid SphericalHeightmapGenerator::generateHeightData(OUT PlanetHeightData& height, const f64v3& normal) const {\n    generateHeightData(height, normal * m_genData->radius, normal);\n}\n\nFloraID SphericalHeightmapGenerator::getTreeID(const Biome* biome, const VoxelPosition2D& facePosition, const f64v3& worldPos) const {\n    // TODO(Ben): Experiment with optimizations with large amounts of flora.\n    f64 noTreeChance = 1.0;\n    f64 totalChance = 0.0;\n    // NOTE: Stack overflow bad mkay\n    f64* chances = (f64*)alloca(sizeof(f64) * biome->trees.size());\n    // Determine chance\n    for (size_t i = 0; i < biome->trees.size(); i++) {\n        auto& t = biome->trees[i];\n        f64 c = t.chance.base;\n        getNoiseValue(worldPos, t.chance.funcs, nullptr, TerrainOp::ADD, c);\n        totalChance += c;\n        chances[i] = totalChance;\n        noTreeChance *= (1.0 - c);\n    }\n    // ITS SLOW\n    std::hash<f64> h;\n    std::uniform_real_distribution<f64> dist(0.0, 1.0);\n    std::mt19937 slowRGen(h(facePosition.pos.x) ^ (h(facePosition.pos.y) << 1));\n    f64 r = dist(slowRGen);\n    if (r < 1.0 - noTreeChance) {\n        // A plant exists, now we determine which one\n        // TODO(Ben): Binary search?\n        f64 roll = dist(slowRGen) * totalChance;\n        for (size_t i = 0; i < biome->trees.size(); i++) {\n            if (roll <= chances[i]) {\n                return biome->trees[i].id;\n            }\n        }\n    }\n    return FLORA_ID_NONE;\n}\n\nFloraID SphericalHeightmapGenerator::getFloraID(const Biome* biome, const VoxelPosition2D& facePosition, const f64v3& worldPos) const {\n    // TODO(Ben): Experiment with optimizations with large amounts of flora.\n    f64 noFloraChance = 1.0;\n    f64 totalChance = 0.0;\n    // NOTE: Stack overflow bad mkay\n    f64* chances = (f64*)alloca(sizeof(f64) * biome->flora.size());\n    // Determine chance\n    for (size_t i = 0; i < biome->flora.size(); i++) {\n        auto& t = biome->flora[i];\n        f64 c = t.chance.base;\n        getNoiseValue(worldPos, t.chance.funcs, nullptr, TerrainOp::ADD, c);\n        totalChance += c;\n        chances[i] = totalChance;\n        noFloraChance *= (1.0 - c);\n    }\n    // Start random generator\n    // ITS SLOW\n    std::hash<f64> h;\n    std::uniform_real_distribution<f64> dist(0.0, 1.0);\n    std::mt19937 slowRGen(h(facePosition.pos.x) ^ (h(facePosition.pos.y) << 1));\n    f64 r = dist(slowRGen);\n    if (r < 1.0 - noFloraChance) {\n        f64 roll = dist(slowRGen) * totalChance;\n        for (size_t i = 0; i < biome->flora.size(); i++) {\n            if (roll <= chances[i]) {\n                return biome->flora[i].id;\n            }\n        }\n    }\n    return FLORA_ID_NONE;\n}\n\nvoid getBaseBiomes(const std::vector<BiomeInfluence> baseBiomeInfluenceMap[BIOME_MAP_WIDTH][BIOME_MAP_WIDTH], f64 x, f64 y, OUT std::map<BiomeInfluence, f64>& rvBiomes) {\n    int ix = (int)x;\n    int iy = (int)y;\n\n    //0 1\n    //2 3\n    /* Interpolate */\n    // Get weights\n    f64 fx = x - (f64)ix;\n    f64 fy = y - (f64)iy;\n    f64 fx1 = 1.0 - fx;\n    f64 fy1 = 1.0 - fy;\n    f64 w0 = fx1 * fy1;\n    f64 w1 = fx * fy1;\n    f64 w2 = fx1 * fy;\n    f64 w3 = fx * fy;\n\n    // Shorter handles\n#define BLIST_0 baseBiomeInfluenceMap[iy][ix]\n#define BLIST_1 baseBiomeInfluenceMap[iy][ix + 1]\n#define BLIST_2 baseBiomeInfluenceMap[iy + 1][ix]\n#define BLIST_3 baseBiomeInfluenceMap[iy + 1][ix + 1]\n\n    // TODO(Ben): Explore padding to ditch ifs?\n    /* Construct list of biomes to generate and assign weights from interpolation. */\n    // Top Left\n    for (auto& b : BLIST_0) {\n        auto it = rvBiomes.find(b);\n        if (it == rvBiomes.end()) {\n            rvBiomes[b] = w0 * b.weight;\n        } else {\n            it->second += w0 * b.weight;\n        }\n    }\n    // Top Right\n    if (ix < BIOME_MAP_WIDTH - 1) {\n        for (auto& b : BLIST_1) {\n            auto it = rvBiomes.find(b);\n            if (it == rvBiomes.end()) {\n                rvBiomes[b] = w1 * b.weight;\n            } else {\n                it->second += w1 * b.weight;\n            }\n        }\n    } else {\n        for (auto& b : BLIST_0) {\n            rvBiomes[b] += w1 * b.weight;\n        }\n    }\n    // Bottom left\n    if (iy < BIOME_MAP_WIDTH - 1) {\n        for (auto& b : BLIST_2) {\n            auto it = rvBiomes.find(b);\n            if (it == rvBiomes.end()) {\n                rvBiomes[b] = w2 * b.weight;\n            } else {\n                it->second += w2 * b.weight;\n            }\n        }\n        // Bottom right\n        if (ix < BIOME_MAP_WIDTH - 1) {\n            for (auto& b : BLIST_3) {\n                auto it = rvBiomes.find(b);\n                if (it == rvBiomes.end()) {\n                    rvBiomes[b] = w3 * b.weight;\n                } else {\n                    it->second += w3 * b.weight;\n                }\n            }\n        } else {\n            for (auto& b : BLIST_2) {\n                rvBiomes[b] += w3 * b.weight;\n            }\n        }\n    } else {\n        for (auto& b : BLIST_0) {\n            rvBiomes[b] += w2 * b.weight;\n        }\n        for (auto& b : BLIST_1) {\n            rvBiomes[b] += w3 * b.weight;\n        }\n    }\n}\n\ninline void SphericalHeightmapGenerator::generateHeightData(OUT PlanetHeightData& height, const f64v3& pos, const f64v3& normal) const {\n    f64 h = getBaseHeightValue(pos);\n    height.height = (f32)(h * VOXELS_PER_M);\n    h *= KM_PER_M;\n    f64 temperature = getTemperatureValue(pos, normal, h);\n    f64 humidity = getHumidityValue(pos, normal, h);\n    height.temperature = (ui8)temperature;\n    height.humidity = (ui8)humidity;\n    height.flora = FLORA_ID_NONE;\n\n    // Base Biome\n    f64 biggestWeight = 0.0;\n    const Biome* bestBiome = m_genData->baseBiomeLookup[height.humidity][height.temperature];\n\n    std::map<BiomeInfluence, f64> baseBiomes;\n    getBaseBiomes(m_genData->baseBiomeInfluenceMap, temperature, humidity, baseBiomes);\n\n    for (auto& bb : baseBiomes) {\n        const Biome* biome = bb.first.b;\n        f64 baseWeight = bb.first.weight * bb.second;\n        // Get base biome terrain\n        f64 newHeight = biome->terrainNoise.base + height.height;\n        getNoiseValue(pos, biome->terrainNoise.funcs, nullptr, TerrainOp::ADD, newHeight);\n        // Mix in height with squared interpolation\n        height.height = (f32)((baseWeight * newHeight) + (1.0 - baseWeight) * (f64)height.height);\n        // Sub biomes\n        recurseChildBiomes(biome, pos, height.height, biggestWeight, bestBiome, baseWeight);\n    }\n    // Mark biome that is the best\n    height.biome = bestBiome;\n}\n\nvoid SphericalHeightmapGenerator::recurseChildBiomes(const Biome* biome, const f64v3& pos, f32& height, f64& biggestWeight, const Biome*& bestBiome, f64 baseWeight) const {\n    // Get child noise value\n    f64 noiseVal = biome->childNoise.base;\n    getNoiseValue(pos, biome->childNoise.funcs, nullptr, TerrainOp::ADD, noiseVal);\n    // Sub biomes\n    for (auto& child : biome->children) {\n        f64 weight = 1.0;\n        // Check if biome is present and get weight\n        { // Noise\n            f64 dx = noiseVal - child->noiseRange.x;\n            f64 dy = child->noiseRange.y - noiseVal;\n            // See which side we are closer to\n            if (ABS(dx) < ABS(dy)) {\n                if (dx < 0) {\n                    continue;\n                }\n                dx *= child->noiseScale.x;\n                if (dx > 1.0) {\n                    dx = 1.0;\n                } else {\n                    weight *= dx;\n                }\n            } else {\n                if (dy < 0) {\n                    continue;\n                }\n                dy *= child->noiseScale.x;\n                if (dy > 1.0) {\n                    dy = 1.0;\n                } else {\n                    weight *= dy;\n                }\n            }\n        }\n        { // Height\n            f64 dx = height - child->heightRange.x;\n            f64 dy = child->heightRange.y - height;\n            // See which side we are closer to\n            if (ABS(dx) < ABS(dy)) {\n                if (dx < 0) {\n                    continue;\n                }\n                dx *= child->heightScale.x;\n                if (dx > 1.0) {\n                    dx = 1.0;\n                } else {\n                    weight *= hermite(dx);\n                }\n            } else {\n                if (dy < 0) {\n                    continue;\n                }\n                dy *= child->heightScale.x;\n                if (dy > 1.0) {\n                    dy = 1.0;\n                } else {\n                    weight *= hermite(dy);\n                }\n            }\n        }\n        // If we reach here, the biome exists.\n        f64 newHeight = child->terrainNoise.base + height;\n        getNoiseValue(pos, child->terrainNoise.funcs, nullptr, TerrainOp::ADD, newHeight);\n        // Biggest weight biome is the next biome\n        if (weight >= biggestWeight) {\n            biggestWeight = weight;\n            bestBiome = child;\n        }\n        weight = baseWeight * weight * weight;\n        // Mix in height with squared interpolation\n        height = (f32)((weight * newHeight) + (1.0 - weight) * height);\n        // Recurse children\n        if (child->children.size() && weight > WEIGHT_THRESHOLD) {\n            recurseChildBiomes(child, pos, height, biggestWeight, bestBiome, weight);\n        }\n    }\n}\n\nf64 SphericalHeightmapGenerator::getBaseHeightValue(const f64v3& pos) const {\n    f64 genHeight = m_genData->baseTerrainFuncs.base;\n    getNoiseValue(pos, m_genData->baseTerrainFuncs.funcs, nullptr, TerrainOp::ADD, genHeight);\n    return genHeight;\n}\n\nf64 SphericalHeightmapGenerator::getTemperatureValue(const f64v3& pos, const f64v3& normal, f64 height) const {\n    f64 genHeight = m_genData->tempTerrainFuncs.base;\n    getNoiseValue(pos, m_genData->tempTerrainFuncs.funcs, nullptr, TerrainOp::ADD, genHeight);\n    return calculateTemperature(m_genData->tempLatitudeFalloff, computeAngleFromNormal(normal), genHeight - glm::max(0.0, m_genData->tempHeightFalloff * height));\n}\n\nf64 SphericalHeightmapGenerator::getHumidityValue(const f64v3& pos, const f64v3& normal, f64 height) const {\n    f64 genHeight = m_genData->humTerrainFuncs.base;\n    getNoiseValue(pos, m_genData->humTerrainFuncs.funcs, nullptr, TerrainOp::ADD, genHeight);\n    return SphericalHeightmapGenerator::calculateHumidity(m_genData->humLatitudeFalloff, computeAngleFromNormal(normal), genHeight - glm::max(0.0, m_genData->humHeightFalloff * height));\n}\n\n// Thanks to tetryds for these\nf64 SphericalHeightmapGenerator::calculateTemperature(f64 range, f64 angle, f64 baseTemp) {\n    f64 tempFalloff = 1.0 - pow(cos(angle), 2.0 * angle);\n\n    if(glm::isnan(tempFalloff))\n        tempFalloff=0.0;\n\n    f64 temp = baseTemp - tempFalloff * range;\n    return glm::clamp(temp, 0.0, 255.0);\n}\n\n// Thanks to tetryds for these\nf64 SphericalHeightmapGenerator::calculateHumidity(f64 range, f64 angle, f64 baseHum) {\n    f64 cos3x = cos(3.0 * angle);\n    f64 humFalloff = 1.0 - (-0.25 * angle + 1.0) * (cos3x * cos3x);\n    f64 hum = baseHum - humFalloff * range;\n    return glm::clamp(hum, 0.0, 255.0);\n}\n\nf64 SphericalHeightmapGenerator::computeAngleFromNormal(const f64v3& normal) {\n    // Compute angle\n    if (abs(normal.y) <= 0.000000001) {\n        // Need to do this to fix an equator bug\n        return 0.0;\n    } else {\n        f64v3 equator = glm::normalize(f64v3(normal.x, 0.000000001, normal.z));\n        return acos(glm::dot(equator, normal));\n    }\n}\n\nf64 doOperation(const TerrainOp& op, f64 a, f64 b) {\n    switch (op) {\n        case TerrainOp::ADD: return a + b;\n        case TerrainOp::SUB: return a - b;\n        case TerrainOp::MUL: return a * b;\n        case TerrainOp::DIV: return a / b;\n    }\n    return 0.0;\n}\n\nvoid SphericalHeightmapGenerator::getNoiseValue(const f64v3& pos,\n                                                const Array<TerrainFuncProperties>& funcs,\n                                                f64* modifier,\n                                                const TerrainOp& op,\n                                                f64& height) const {\n\n    // NOTE: Make sure this implementation matches NoiseShaderGenerator::addNoiseFunctions()\n    for (size_t f = 0; f < funcs.size(); ++f) {\n        auto& fn = funcs[f];\n\n        f64 h = 0.0;\n        f64* nextMod;\n        TerrainOp nextOp;\n        // Check if its not a noise function\n        if (fn.func == TerrainStage::CONSTANT) {\n            nextMod = &h;\n            h = fn.low;\n            // Apply parent before clamping\n            if (modifier) {\n                h = doOperation(op, h, *modifier);\n            }\n            // Optional clamp if both fields are not 0.0\n            if (fn.clamp[0] != 0.0 || fn.clamp[1] != 0.0) {\n                h = glm::clamp(*modifier, (f64)fn.clamp[0], (f64)fn.clamp[1]);\n            }\n            nextOp = fn.op;\n        } else if (fn.func == TerrainStage::PASS_THROUGH) {\n            nextMod = modifier;\n            // Apply parent before clamping\n            if (modifier) {\n                h = doOperation(op, *modifier, fn.low);\n                // Optional clamp if both fields are not 0.0\n                if (fn.clamp[0] != 0.0 || fn.clamp[1] != 0.0) {\n                    h = glm::clamp(h, fn.clamp[0], fn.clamp[1]);\n                }\n            }\n            nextOp = op;\n        } else if (fn.func == TerrainStage::SQUARED) {\n            nextMod = modifier;\n            // Apply parent before clamping\n            if (modifier) {\n                *modifier = (*modifier) * (*modifier);\n                // Optional clamp if both fields are not 0.0\n                if (fn.clamp[0] != 0.0 || fn.clamp[1] != 0.0) {\n                    h = glm::clamp(h, fn.clamp[0], fn.clamp[1]);\n                }\n            }\n            nextOp = op;\n        } else if (fn.func == TerrainStage::CUBED) {\n            nextMod = modifier;\n            // Apply parent before clamping\n            if (modifier) {\n                *modifier = (*modifier) * (*modifier) * (*modifier);\n                // Optional clamp if both fields are not 0.0\n                if (fn.clamp[0] != 0.0 || fn.clamp[1] != 0.0) {\n                    h = glm::clamp(h, fn.clamp[0], fn.clamp[1]);\n                }\n            }\n            nextOp = op;\n        } else { // It's a noise function\n            nextMod = &h;\n            f64v2 ff;\n            f64 tmp;\n            f64 total = 0.0;\n            f64 maxAmplitude = 0.0;\n            f64 amplitude = 1.0;\n            f64 frequency = fn.frequency;\n            for (int i = 0; i < fn.octaves; i++) {\n                // TODO(Ben): Could cut branching\n                switch (fn.func) {\n                    case TerrainStage::CUBED_NOISE:\n                    case TerrainStage::SQUARED_NOISE:\n                    case TerrainStage::NOISE:\n                        total += Noise::raw(pos.x * frequency, pos.y * frequency, pos.z * frequency) * amplitude;\n                        break;\n                    case TerrainStage::RIDGED_NOISE:\n                        total += ((1.0 - glm::abs(Noise::raw(pos.x * frequency, pos.y * frequency, pos.z * frequency))) * 2.0 - 1.0) * amplitude;\n                        break;\n                    case TerrainStage::ABS_NOISE:\n                        total += glm::abs(Noise::raw(pos.x * frequency, pos.y * frequency, pos.z * frequency)) * amplitude;\n                        break;\n                    case TerrainStage::CELLULAR_NOISE:\n                        ff = Noise::cellular(pos * (f64)frequency);\n                        total += (ff.y - ff.x) * amplitude;\n                        break;\n                    case TerrainStage::CELLULAR_SQUARED_NOISE:\n                        ff = Noise::cellular(pos * (f64)frequency);\n                        tmp = ff.y - ff.x;\n                        total += tmp * tmp * amplitude;\n                        break;\n                    case TerrainStage::CELLULAR_CUBED_NOISE:\n                        ff = Noise::cellular(pos * (f64)frequency);\n                        tmp = ff.y - ff.x;\n                        total += tmp * tmp * tmp * amplitude;\n                        break;\n                    default:\n                        break;\n                }\n                frequency *= 2.0;\n                maxAmplitude += amplitude;\n                amplitude *= fn.persistence;\n            }\n            total = (total / maxAmplitude);\n            // Handle any post processes per noise\n            switch (fn.func) {\n                case TerrainStage::CUBED_NOISE:\n                    total = total * total * total;\n                    break;\n                case TerrainStage::SQUARED_NOISE:\n                    total = total * total;\n                    break;\n                default:\n                    break;\n            }\n            // Conditional scaling. \n            if (fn.low != -1.0 || fn.high != 1.0) {\n                h = total * (fn.high - fn.low) * 0.5 + (fn.high + fn.low) * 0.5;\n            } else {\n                h = total;\n            }\n            // Optional clamp if both fields are not 0.0\n            if (fn.clamp[0] != 0.0 || fn.clamp[1] != 0.0) {\n                h = glm::clamp(h, (f64)fn.clamp[0], (f64)fn.clamp[1]);\n            }\n            // Apply modifier from parent if needed\n            if (modifier) {\n                h = doOperation(op, h, *modifier);\n            }\n            nextOp = fn.op;\n        }\n\n        if (fn.children.size()) {\n            // Early exit for speed\n            if (!(nextOp == TerrainOp::MUL && *nextMod == 0.0)) {\n                getNoiseValue(pos, fn.children, nextMod, nextOp, height);\n            }\n        } else {\n            height = doOperation(fn.op, height, h);\n        }\n    }\n}\n"
  },
  {
    "path": "SoA/SphericalHeightmapGenerator.h",
    "content": "///\n/// SphericalTerrainCpuGenerator.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Generates spherical terrain data and meshes for a planet using the CPU.\n/// Each planet should own one.\n///\n\n#pragma once\n\n#ifndef SphericalTerrainCpuGenerator_h__\n#define SphericalTerrainCpuGenerator_h__\n\n#include \"TerrainPatch.h\"\n#include \"TerrainPatchMesher.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"PlanetGenData.h\"\n\n#include <Vorb/Event.hpp>\n\nstruct NoiseBase;\nstruct PlanetHeightData;\n\n// TODO(Ben): Implement this\ntypedef Delegate<void, PlanetHeightData&, f64v3, PlanetGenData> heightmapGenFunction;\n\nclass SphericalHeightmapGenerator {\npublic:\n    void init(const PlanetGenData* planetGenData);\n\n    /// Gets the height at a specific face position.\n    void generateHeightData(OUT PlanetHeightData& height, const VoxelPosition2D& facePosition) const;\n    void generateHeightData(OUT PlanetHeightData& height, const f64v3& normal) const;\n\n    // Gets the tree id that should be at a specific worldspace position\n    FloraID getTreeID(const Biome* biome, const VoxelPosition2D& facePosition, const f64v3& worldPos) const;\n    // Gets the flora id that should be at a specific worldspace position\n    FloraID getFloraID(const Biome* biome, const VoxelPosition2D& facePosition, const f64v3& worldPos) const;\n    \n    const PlanetGenData* getGenData() const { return m_genData; }\nprivate:\n    void generateHeightData(OUT PlanetHeightData& height, const f64v3& pos, const f64v3& normal) const;\n    void recurseChildBiomes(const Biome* biome, const f64v3& pos, f32& height, f64& biggestWeight, const Biome*& bestBiome, f64 baseWeight) const;\n    \n    /// Gets noise value using terrainFuncs\n    /// @return the noise value\n    void getNoiseValue(const f64v3& pos,\n                      const Array<TerrainFuncProperties>& funcs,\n                      f64* modifier,\n                      const TerrainOp& op,\n                      f64& height) const;\n\n    f64 getBaseHeightValue(const f64v3& pos) const;\n    f64 getTemperatureValue(const f64v3& pos, const f64v3& normal, f64 height) const;\n    f64 getHumidityValue(const f64v3& pos, const f64v3& normal, f64 height) const;\n\n    /// Calculates temperature based on angle with equator\n    /// @param range: The range to scale between\n    /// @angle: Angle from equator\n    /// @param baseTemp: Base temperature\n    static f64 calculateTemperature(f64 range, f64 angle, f64 baseTemp);\n    /// Calculates humidity based on angle with equator\n    /// @param range: The range to scale between\n    /// @angle: Angle from equator\n    /// @param baseTemp: Base humidity\n    static f64 calculateHumidity(f64 range, f64 angle, f64 baseHum);\n\n    // Computes angle from normalized position\n    static f64 computeAngleFromNormal(const f64v3& normal);\n\n    const PlanetGenData* m_genData = nullptr; ///< Planet generation data for this generator\n};\n\n#endif // SphericalTerrainCpuGenerator_h__\n"
  },
  {
    "path": "SoA/SphericalTerrainComponentRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SphericalTerrainComponentRenderer.h\"\n\n#include \"Camera.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"TerrainPatchMeshManager.h\"\n#include \"TerrainPatch.h\"\n#include \"soaUtils.h\"\n#include \"ShaderLoader.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/ShaderManager.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/utils.h>\n\nSphericalTerrainComponentRenderer::~SphericalTerrainComponentRenderer() {\n    dispose();\n}\n\nvoid SphericalTerrainComponentRenderer::initGL() {\n    m_terrainProgram = ShaderLoader::createProgramFromFile(\"Shaders/SphericalTerrain/SphericalTerrain.vert\",\n                                                           \"Shaders/SphericalTerrain/SphericalTerrain.frag\");\n    // Set constant uniforms\n    m_terrainProgram.use();\n    glUniform1i(m_terrainProgram.getUniform(\"unColorMap\"), 1);\n    glUniform1i(m_terrainProgram.getUniform(\"unGrassTexture\"), 2);\n    glUniform1i(m_terrainProgram.getUniform(\"unRockTexture\"), 3);\n     m_terrainProgram.unuse();\n\n    m_waterProgram = ShaderLoader::createProgramFromFile(\"Shaders/SphericalTerrain/SphericalWater.vert\",\n                                                         \"Shaders/SphericalTerrain/SphericalWater.frag\");\n    // Set constant uniforms\n    m_waterProgram.use();\n    glUniform1i(m_waterProgram.getUniform(\"unNormalMap\"), 0);\n    glUniform1i(m_waterProgram.getUniform(\"unColorMap\"), 1);\n    m_waterProgram.unuse();\n}\n\n// TODO: Is this implementation complete?\nvoid SphericalTerrainComponentRenderer::draw(SphericalTerrainComponent& cmp,\n                                             const Camera* camera,\n                                             const f32v3& lightDir,\n                                             const f64v3& position,\n                                             const f32 zCoef,\n                                             const SpaceLightComponent* spComponent VORB_UNUSED,\n                                             const AxisRotationComponent* arComponent,\n                                             const AtmosphereComponent* aComponent) {\n    if (cmp.patches) {\n        \n        f64v3 relativeCameraPos = camera->getPosition() - position;\n\n        // Sort meshes\n        cmp.meshManager->sortSpericalMeshes(relativeCameraPos);\n        // Draw spherical patches\n        if (cmp.alpha >= 1.0f) {\n            cmp.meshManager->drawSphericalMeshes(relativeCameraPos, camera,\n                                                 arComponent->currentOrientation,\n                                                 m_terrainProgram, m_waterProgram,\n                                                 lightDir,\n                                                 1.0f,\n                                                 zCoef,\n                                                 aComponent,\n                                                 true);\n        }\n    }\n}\n\nvoid SphericalTerrainComponentRenderer::dispose() {\n    if (m_terrainProgram.isCreated()) m_terrainProgram.dispose();\n    if (m_waterProgram.isCreated()) m_waterProgram.dispose();\n}\n"
  },
  {
    "path": "SoA/SphericalTerrainComponentRenderer.h",
    "content": "///\n/// SphericalTerrainComponentRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renders spherical terrain components\n///\n\n#pragma once\n\n#ifndef SphericalTerrainComponentRenderer_h__\n#define SphericalTerrainComponentRenderer_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/GLProgram.h>\n\nclass Camera;\nstruct AtmosphereComponent;\nstruct AxisRotationComponent;\nstruct NamePositionComponent;\nstruct SpaceLightComponent;\nstruct SphericalTerrainComponent;\n\nclass SphericalTerrainComponentRenderer {\npublic:\n    ~SphericalTerrainComponentRenderer();\n    void initGL();\n    void draw(SphericalTerrainComponent& cmp,\n              const Camera* camera,\n              const f32v3& lightDir,\n              const f64v3& position,\n              const f32 zCoef,\n              const SpaceLightComponent* spComponent,\n              const AxisRotationComponent* arComponent,\n              const AtmosphereComponent* aComponent);\n    void dispose();\nprivate:\n    vg::GLProgram m_terrainProgram;\n    vg::GLProgram m_waterProgram;\n};\n\n#endif // SphericalTerrainComponentRenderer_h__\n"
  },
  {
    "path": "SoA/SphericalTerrainComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SphericalTerrainComponentUpdater.h\"\n\n#include \"SoAState.h\"\n#include \"SpaceSystem.h\"\n#include \"SpaceSystemAssemblages.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"SphericalHeightmapGenerator.h\"\n#include \"TerrainPatchMeshManager.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"PlanetGenLoader.h\"\n#include \"soaUtils.h\"\n\nvoid SphericalTerrainComponentUpdater::update(SoaState* state, const f64v3& cameraPos) {\n\n    SpaceSystem* spaceSystem = state->spaceSystem;\n    for (auto& it : spaceSystem->sphericalTerrain) {\n        SphericalTerrainComponent& stCmp = it.second;\n    \n        const NamePositionComponent& npComponent = spaceSystem->namePosition.get(stCmp.namePositionComponent);\n        const AxisRotationComponent& arComponent = spaceSystem->axisRotation.get(stCmp.axisRotationComponent);\n        /// Calculate camera distance\n        f64v3 relativeCameraPos = arComponent.invCurrentOrientation * (cameraPos - npComponent.position);\n        stCmp.distance = glm::length(relativeCameraPos);\n\n        // Lazy random planet loading\n        if (stCmp.distance <= LOAD_DIST && !stCmp.planetGenData) {\n            PlanetGenLoader loader;\n            loader.init(state->systemIoManager);\n            PlanetGenData* data = loader.getRandomGenData((f32)stCmp.radius);\n            stCmp.meshManager = new TerrainPatchMeshManager(data);\n            stCmp.cpuGenerator = new SphericalHeightmapGenerator;\n            stCmp.cpuGenerator->init(data);\n            // Do this last to prevent race condition with regular update\n            data->radius = stCmp.radius;\n            stCmp.planetGenData = data;\n            stCmp.sphericalTerrainData->generator = stCmp.cpuGenerator;\n            stCmp.sphericalTerrainData->meshManager = stCmp.meshManager;\n        }\n\n        // Animation for fade\n        if (stCmp.needsVoxelComponent) {\n            stCmp.alpha -= TERRAIN_ALPHA_STEP;\n            if (stCmp.alpha < 0.0f) {\n                stCmp.alpha = 0.0f;\n                // Force it to unload\n                stCmp.distance = LOAD_DIST * 10.0;\n            }\n        } else {\n            stCmp.alpha += TERRAIN_ALPHA_STEP;\n            if (stCmp.alpha > 1.0f) stCmp.alpha = 1.0f;\n        }\n\n        if (stCmp.distance <= LOAD_DIST) {\n           \n            if (stCmp.planetGenData && !stCmp.needsVoxelComponent) {\n                // Allocate if needed\n                if (!stCmp.patches) {\n                    initPatches(stCmp);\n                }\n\n                // Update patches\n                for (int i = 0; i < ST_TOTAL_PATCHES; i++) {\n                    stCmp.patches[i].update(relativeCameraPos);\n                }\n            }\n        } else {\n            // Out of range, delete everything\n            if (stCmp.patches) {\n                delete[] stCmp.patches;\n                stCmp.patches = nullptr;\n            }\n        }\n\n        updateVoxelComponentLogic(state, it.first, stCmp);\n    }\n}\n\nvoid SphericalTerrainComponentUpdater::glUpdate(const SoaState* soaState) {\n    auto& spaceSystem = soaState->spaceSystem;\n    for (auto& it : spaceSystem->sphericalTerrain) {\n        SphericalTerrainComponent& stCmp = it.second;\n        \n        if (stCmp.meshManager && it.second.alpha > 0.0f) stCmp.meshManager->update();\n    }\n}\n\nvoid SphericalTerrainComponentUpdater::initPatches(SphericalTerrainComponent& cmp) {\n    const f64& patchWidth = cmp.sphericalTerrainData->patchWidth;\n\n    // Allocate top level patches\n    cmp.patches = new TerrainPatch[ST_TOTAL_PATCHES];\n\n    int center = ST_PATCH_ROW / 2;\n    f64v2 gridPos;\n    int index = 0;\n\n    // Init all the top level patches for each of the 6 grids\n    for (int face = 0; face < NUM_FACES; face++) {\n        for (int z = 0; z < ST_PATCH_ROW; z++) {\n            for (int x = 0; x < ST_PATCH_ROW; x++) {\n                auto& p = cmp.patches[index++];\n                gridPos.x = (x - center) * patchWidth;\n                gridPos.y = (z - center) * patchWidth;\n                p.init(gridPos, static_cast<WorldCubeFace>(face),\n                       0, cmp.sphericalTerrainData, patchWidth);\n            }\n        }\n    }\n}\n\nvoid SphericalTerrainComponentUpdater::updateVoxelComponentLogic(SoaState* state, vecs::EntityID eid, SphericalTerrainComponent& stCmp) {\n    SpaceSystem* spaceSystem = state->spaceSystem;\n    // Handle voxel component\n    if (stCmp.needsVoxelComponent) {\n        // Check for creating a new component\n        if (!stCmp.sphericalVoxelComponent) {\n            // TODO(Ben): FarTerrain should be clientSide only\n            // Add far terrain component (CLIENT SIDE)\n            stCmp.farTerrainComponent = SpaceSystemAssemblages::addFarTerrainComponent(spaceSystem, eid, stCmp,\n                                                                                       stCmp.startVoxelPosition.face);\n            // Add spherical voxel component (SERVER SIDE)\n            stCmp.sphericalVoxelComponent = SpaceSystemAssemblages::addSphericalVoxelComponent(spaceSystem, eid,\n                                                                                               spaceSystem->sphericalTerrain.getComponentID(eid),\n                                                                                               stCmp.farTerrainComponent,\n                                                                                               stCmp.axisRotationComponent,\n                                                                                               stCmp.namePositionComponent,\n                                                                                               stCmp.startVoxelPosition.face,\n                                                                                               state);\n        }\n\n        // Far terrain face transition\n        if (stCmp.transitionFace != FACE_NONE) {\n            static const f32 FACE_TRANS_DEC = 0.02f;\n            if (stCmp.faceTransTime == START_FACE_TRANS) stCmp.needsFaceTransitionAnimation = true;\n            stCmp.faceTransTime -= FACE_TRANS_DEC;\n            if (stCmp.faceTransTime <= 0.0f) {\n                // TODO(Ben): maybe tell voxels to switch to new face rather than just deleting\n                //spaceSystem->m_sphericalVoxelCT.get(stCmp.sphericalVoxelComponent).transitionFace = stCmp.transitionFace;\n                SpaceSystemAssemblages::removeSphericalVoxelComponent(spaceSystem, eid);\n                // Add spherical voxel component (SERVER SIDE)\n                stCmp.sphericalVoxelComponent = SpaceSystemAssemblages::addSphericalVoxelComponent(spaceSystem, eid,\n                                                                                                   spaceSystem->sphericalTerrain.getComponentID(eid),\n                                                                                                   stCmp.farTerrainComponent,\n                                                                                                   stCmp.axisRotationComponent,\n                                                                                                   stCmp.namePositionComponent,\n                                                                                                   stCmp.transitionFace,\n                                                                                                   state);\n                // Reload the terrain\n                auto& ftCmp = spaceSystem->farTerrain.get(stCmp.farTerrainComponent);\n                ftCmp.transitionFace = stCmp.transitionFace;\n                stCmp.transitionFace = FACE_NONE;\n                stCmp.faceTransTime = 0.0f;\n                std::cout << \" RE-INIT Voxels\\n\";\n            }\n        } else if (!stCmp.needsFaceTransitionAnimation) {\n            stCmp.faceTransTime = 1.0f;\n        }\n    } else {\n        // Check for deleting components\n        // TODO(Ben): We need to do refcounting for MP!\n        if (stCmp.sphericalVoxelComponent) {\n            // Mark far terrain for fadeout\n            auto& ftCmp = spaceSystem->farTerrain.get(stCmp.farTerrainComponent);\n\n            if (!ftCmp.shouldFade) {\n                ftCmp.shouldFade = true;\n                ftCmp.alpha = TERRAIN_DEC_START_ALPHA;\n            } else if (ftCmp.alpha < 0.0f) {\n                // We are faded out, so deallocate\n                SpaceSystemAssemblages::removeSphericalVoxelComponent(spaceSystem, eid);\n                SpaceSystemAssemblages::removeFarTerrainComponent(spaceSystem, eid);\n                stCmp.sphericalVoxelComponent = 0;\n                stCmp.farTerrainComponent = 0;\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "SoA/SphericalTerrainComponentUpdater.h",
    "content": "///\n/// SphericalTerrainComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates SphericalTerrainComponents.\n///\n\n#pragma once\n\n#ifndef SphericalTerrainComponentUpdater_h__\n#define SphericalTerrainComponentUpdater_h__\n\nclass SpaceSystem;\nstruct SoaState;\nstruct SphericalTerrainComponent;\n\n#include \"TerrainPatch.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/ecs/ECS.h>\n\n#define LOAD_DIST 800000.0\n// Should be even\n#define ST_PATCH_ROW 2  \n#define NUM_FACES 6\nconst int ST_PATCHES_PER_FACE = (ST_PATCH_ROW * ST_PATCH_ROW);\nconst int ST_TOTAL_PATCHES = ST_PATCHES_PER_FACE * NUM_FACES;\n\nclass SphericalTerrainComponentUpdater {\npublic:\n    void update(SoaState* state, const f64v3& cameraPos);\n\n    /// Updates openGL specific stuff. Call on render thread\n    void glUpdate(const SoaState* soaState);\n\nprivate:\n    void initPatches(SphericalTerrainComponent& cmp);\n    void updateVoxelComponentLogic(SoaState* state, vecs::EntityID eid, SphericalTerrainComponent& stCmp);\n};\n\n#endif // SphericalTerrainComponentUpdater_h__\n"
  },
  {
    "path": "SoA/SphericalVoxelComponentUpdater.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SphericalVoxelComponentUpdater.h\"\n\n#include <SDL2/SDL_timer.h> // For SDL_GetTicks\n\n#include \"Chunk.h\"\n#include \"ChunkAllocator.h\"\n#include \"ChunkGrid.h\"\n#include \"ChunkIOManager.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkMeshTask.h\"\n#include \"ChunkRenderer.h\"\n#include \"ChunkUpdater.h\"\n#include \"GameSystem.h\"\n#include \"GenerateTask.h\"\n#include \"PlanetGenData.h\"\n#include \"SoaOptions.h\"\n#include \"SoAState.h\"\n#include \"SpaceSystem.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"VoxelSpaceConversions.h\"\n#include \"soaUtils.h\"\n\n#include <Vorb/voxel/VoxCommon.h>\n\nvoid SphericalVoxelComponentUpdater::update(const SoaState* soaState) {\n    SpaceSystem* spaceSystem = soaState->spaceSystem;\n    // GameSystem* gameSystem = soaState->gameSystem;\n    if (spaceSystem->sphericalVoxel.getComponentListSize() > 1) {\n        for (auto& it : spaceSystem->sphericalVoxel) {\n            if (it.second.chunkGrids) {\n                updateComponent(it.second);\n            }\n        }\n    }\n}\n\nvoid SphericalVoxelComponentUpdater::updateComponent(SphericalVoxelComponent& cmp) {\n    m_cmp = &cmp;\n    // Update each world cube face\n    for (int i = 0; i < 6; i++) {\n        updateChunks(cmp.chunkGrids[i], true);\n        cmp.chunkGrids[i].update();\n    }\n}\n\n// TODO: Implement and remove VORB_UNUSED tags.\nvoid SphericalVoxelComponentUpdater::updateChunks(ChunkGrid& grid VORB_UNUSED, bool doGen VORB_UNUSED) {\n    // Get render distance squared\n    f32 renderDist2 = (soaOptions.get(OPT_VOXEL_RENDER_DISTANCE).value.f + (f32)CHUNK_WIDTH);\n    renderDist2 *= renderDist2;\n\n}\n\n"
  },
  {
    "path": "SoA/SphericalVoxelComponentUpdater.h",
    "content": "///\n/// SphericalVoxelComponentUpdater.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 8 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Updates spherical voxel components\n///\n\n#pragma once\n\n#ifndef SphericalVoxelComponentUpdater_h__\n#define SphericalVoxelComponentUpdater_h__\n\n#include \"ChunkHandle.h\"\n\nclass Camera;\nclass Chunk;\nclass FloraTask;\nclass Frustum;\nclass GameSystem;\nclass GenerateTask;\nclass GeneratedTreeNodes;\nclass ChunkMeshTask;\nclass ChunkGrid;\nstruct SoaState;\nclass SpaceSystem;\nstruct AxisRotationComponent;\nstruct NamePositionComponent;\nstruct SphericalVoxelComponent;\nstruct VoxelPosition3D;\n\n#include \"VoxelCoordinateSpaces.h\"\n\nclass SphericalVoxelComponentUpdater {\npublic:\n    void update(const SoaState* soaState);\n\nprivate:\n    void updateComponent(SphericalVoxelComponent& cmp);\n\n    void updateChunks(ChunkGrid& grid, bool doGen);\n\n    SphericalVoxelComponent* m_cmp = nullptr; ///< Component we are updating\n};\n\n#endif // SphericalVoxelComponentUpdater_h__\n"
  },
  {
    "path": "SoA/SsaoRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SsaoRenderStage.h\"\n\n#include <Vorb/Random.h>\n#include <Vorb/graphics/SamplerState.h>\n#include <Vorb/utils.h>\n\n#include <random>\n\n#include \"Errors.h\"\n#include \"Camera.h\"\n#include \"ShaderLoader.h\"\n\nvoid SSAORenderStage::hook(vg::FullQuadVBO* quad, unsigned int width, unsigned int height) {\n    std::mt19937 randGenerator;\n    std::uniform_real_distribution<f32> range1(-1.0f, 1.0f);\n    std::uniform_real_distribution<f32> range2(0.0f, 1.0f);\n    \n    m_quad = quad;\n    m_texNoise.width = SSAO_NOISE_TEXTURE_SIZE;\n    m_texNoise.height = SSAO_NOISE_TEXTURE_SIZE;\n\n    // Generate random data\n    i32 pixCount = m_texNoise.width * m_texNoise.height;\n    f32v2* data = new f32v2[pixCount];\n    Random r(clock());\n    for (i32 i = 0; i < pixCount; i++) {\n        // TODO(Ben): vec3?\n        data[i].x = range1(randGenerator);\n        data[i].y = range1(randGenerator);\n        data[i] = glm::normalize(data[i]);\n    }\n\n    // Build noise texture\n    glGenTextures(1, &m_texNoise.id);\n    glBindTexture(GL_TEXTURE_2D, m_texNoise.id);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, m_texNoise.width, m_texNoise.height, 0, GL_RG, GL_FLOAT, data);\n    vg::SamplerState::POINT_WRAP.set(GL_TEXTURE_2D);\n    glBindTexture(GL_TEXTURE_2D, 0);\n    delete[] data;\n\n    m_ssaoTarget.setSize(width, height);\n    m_ssaoTarget.init(vg::TextureInternalFormat::R32F);\n    \n    m_sampleKernel.resize(SSAO_SAMPLE_KERNEL_SIZE);\n    for (unsigned int i = 0; i < SSAO_SAMPLE_KERNEL_SIZE; i++) {\n        m_sampleKernel[i] = glm::normalize(f32v3(range1(randGenerator),\n                                           range1(randGenerator),\n                                           range2(randGenerator)));\n        // Use accelerating interpolation\n        f32 scale = (f32)i / (f32)SSAO_SAMPLE_KERNEL_SIZE;\n        scale = lerp(0.1f, 1.0f, scale * scale);\n        m_sampleKernel[i] *= scale;\n    }\n}\n\nvoid SSAORenderStage::dispose(StaticLoadContext& context VORB_MAYBE_UNUSED)\n{\n    if (m_texNoise.id) {\n        glDeleteTextures(1, &m_texNoise.id);\n        m_texNoise.id = 0;\n    }\n    m_ssaoShader.dispose();\n    m_ssaoTarget.dispose();\n    m_blurShader.dispose();\n}\n\nvoid SSAORenderStage::render(const Camera* camera)\n{\n    glDisable(GL_BLEND);\n    glDisable(GL_DEPTH_TEST);\n\n    const f32m4& projectionMatrix = camera->getProjectionMatrix();\n    const f32m4& viewMatrix = camera->getViewMatrix();\n\n    { // SSAO pass      \n        m_ssaoTarget.use();\n        glClear(GL_COLOR_BUFFER_BIT);\n\n        // Bind textures\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, m_depthTexture);\n        glActiveTexture(GL_TEXTURE1);\n        glBindTexture(GL_TEXTURE_2D, m_normalTexture);\n        glActiveTexture(GL_TEXTURE2);\n        glBindTexture(GL_TEXTURE_2D, m_texNoise.id);\n\n        // Lazy shader init\n        // TODO(Ben): Make it not lazy\n        if (!m_ssaoShader.isCreated()) {\n            m_ssaoShader = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\", \"Shaders/PostProcessing/SSAO.frag\");\n            m_ssaoShader.use();\n            glUniform1i(m_ssaoShader.getUniform(\"unTexDepth\"), 0);\n            glUniform1i(m_ssaoShader.getUniform(\"unTexNormal\"), 1);\n            glUniform1i(m_ssaoShader.getUniform(\"unTexNoise\"), 2);\n            glUniform3fv(glGetUniformLocation(m_ssaoShader.getID(), \"unSampleKernel\"), m_sampleKernel.size(), &m_sampleKernel.data()->x);\n            glUniform2f(m_ssaoShader.getUniform(\"unNoiseScale\"),\n                        (f32)m_ssaoTarget.getWidth() / SSAO_NOISE_TEXTURE_SIZE,\n                        (f32)m_ssaoTarget.getHeight() / SSAO_NOISE_TEXTURE_SIZE);\n            \n        }\n        else {\n            m_ssaoShader.use();\n        }\n\n        glUniformMatrix4fv(m_ssaoShader.getUniform(\"unViewMatrix\"), 1, false, &viewMatrix[0][0]);\n        glUniformMatrix4fv(m_ssaoShader.getUniform(\"unProjectionMatrix\"), 1, false, &projectionMatrix[0][0]);\n        glUniformMatrix4fv(m_ssaoShader.getUniform(\"unInvProjectionMatrix\"), 1, false, &glm::inverse(projectionMatrix)[0][0]);\n\n        m_quad->draw();\n    }\n\n    { // Blur pass\n        // Bind hdr framebuffer\n        glBindFramebuffer(GL_FRAMEBUFFER, m_hdrFrameBuffer);\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, m_colorTexture);\n        glActiveTexture(GL_TEXTURE1);\n        glBindTexture(GL_TEXTURE_2D, m_ssaoTarget.getTextureID());\n\n        // Lazy shader init\n        // TODO(Ben): Make it not lazy\n        if (!m_blurShader.isCreated()) {\n            m_blurShader = ShaderLoader::createProgramFromFile(\"Shaders/PostProcessing/PassThrough.vert\", \"Shaders/PostProcessing/SSAOBlur.frag\");\n            m_blurShader.use();\n            glUniform1i(m_blurShader.getUniform(\"unTexColor\"), 0);\n            glUniform1i(m_blurShader.getUniform(\"unTexSSAO\"), 1);\n            glUniform1f(m_blurShader.getUniform(\"unBlurAmount\"), (float)SSAO_BLUR_AMOUNT);\n        } else {\n            m_blurShader.use();\n        }\n\n        m_quad->draw();\n\n        vg::GLProgram::unuse();\n    }\n\n    glEnable(GL_DEPTH_TEST);\n    glEnable(GL_BLEND);\n}\n\nvoid SSAORenderStage::reloadShaders()\n{\n    m_ssaoShader.dispose();\n    m_blurShader.dispose();\n}"
  },
  {
    "path": "SoA/SsaoRenderStage.h",
    "content": "#pragma once\n\n#include \"IRenderStage.h\"\n\n#define SSAO_NOISE_TEXTURE_SIZE 4\n#define SSAO_SAMPLE_KERNEL_SIZE 32\n#define SSAO_BLUR_AMOUNT 2\n\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GLRenderTarget.h>\n#include <Vorb/graphics/RTSwapChain.hpp>\n#include <Vorb/graphics/Texture.h>\n\n#include <vector>\n\nclass SSAORenderStage : public IRenderStage\n{\npublic:\n    void hook(vg::FullQuadVBO* quad, unsigned int width, unsigned int height);\n\n    virtual void dispose(StaticLoadContext& context) override;\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera = nullptr) override;\n\n\tinline void set(VGTexture depthTexture, VGTexture normalTexture, VGTexture colorTexture, VGFramebuffer hdrFrameBuffer) {\n        m_depthTexture = depthTexture;\n        m_normalTexture = normalTexture;\n        m_colorTexture = colorTexture;\n        m_hdrFrameBuffer = hdrFrameBuffer;\n    }\n    void reloadShaders();\nprivate:\n    vg::GLProgram m_ssaoShader; ///< SSAO effect\n    vg::GLRenderTarget m_ssaoTarget; ///< SSAO render target\n    vg::GLProgram m_blurShader; ///< Blurring to reduce noise\n    vg::FullQuadVBO* m_quad; ///< For use in processing through data\n    vg::Texture m_texNoise; ///< A noise texture to make low sample amounts less obvious\n    VGTexture m_depthTexture;\n    VGTexture m_normalTexture;\n    VGTexture m_colorTexture;\n    VGFramebuffer m_hdrFrameBuffer;\n    std::vector<f32v3> m_sampleKernel;\n};"
  },
  {
    "path": "SoA/StarComponentRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"StarComponentRenderer.h\"\n\n#include \"Errors.h\"\n#include \"ModPathResolver.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"soaUtils.h\"\n\n#include <Vorb/MeshGenerators.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/RasterizerState.h>\n#include <Vorb/graphics/ShaderManager.h>\n#include <Vorb/graphics/SamplerState.h>\n#include <Vorb/utils.h>\n\n#include <glm/gtx/transform.hpp>\n\n#define MIN_TMP 800.0\n#define TMP_RANGE 29200.0\n#define ICOSPHERE_SUBDIVISIONS 5\n\nnamespace {\n    const cString OCCLUSION_VERT_SRC = R\"(\nuniform vec3 unCenterScreenspace;\nuniform float unSize;\nin vec2 vPosition;\nvoid main() {\n    gl_Position.xyz = unCenterScreenspace;\n    gl_Position.xy += vPosition * unSize;\n\tgl_Position.w = 1.0;\n}\n\n)\";\n    const cString OCCLUSION_FRAG_SRC = R\"(\nout vec4 pColor;\nvoid main() {\n    pColor = vec4(0.0, 0.0, 0.0, 0.0);\n}\n)\";\n}\n\nStarComponentRenderer::StarComponentRenderer() {\n    // Empty\n}\n\nStarComponentRenderer::~StarComponentRenderer() {\n    dispose();\n}\n\nvoid StarComponentRenderer::init(const ModPathResolver* textureResolver) {\n    m_textureResolver = textureResolver;\n    m_tempColorMap.width = std::numeric_limits<ui32>::max();\n}\n\nvoid StarComponentRenderer::initGL() {\n    if (!m_starProgram.isCreated()) buildShaders();\n    if (!m_sVbo) buildMesh();\n    if (m_tempColorMap.width == std::numeric_limits<ui32>::max()) loadTempColorMap();\n}\n\nvoid StarComponentRenderer::drawStar(const StarComponent& sCmp,\n                                     const f32m4& VP,\n                                     const f64q& orientation,\n                                     const f32v3& relCamPos,\n                                     const f32 zCoef) {\n    if (sCmp.visibility == 0.0f) return;\n\n    m_starProgram.use();\n\n    // Calculate color\n    f32v3 tColor = calculateStarColor(sCmp) + getTempColorShift(sCmp);\n\n    // Convert f64q to f32q\n    f32q orientationF32;\n    orientationF32.x = (f32)orientation.x;\n    orientationF32.y = (f32)orientation.y;\n    orientationF32.z = (f32)orientation.z;\n    orientationF32.w = (f32)orientation.w;\n\n    // Convert to matrix\n    f32m4 rotationMatrix = glm::toMat4(orientationF32);\n\n    // Set up matrix\n    f32m4 WVP(1.0);\n    setMatrixTranslation(WVP, -relCamPos);\n    WVP = VP * WVP * glm::scale(f32v3(sCmp.radius)) * rotationMatrix;\n\n    // Upload uniforms\n    // Upload uniforms\n    static f64 dt = 0.0;\n    dt += 0.0001;\n    glUniform1f(unDT, (f32)dt);\n    glUniformMatrix4fv(unWVP, 1, GL_FALSE, &WVP[0][0]);\n    glUniform3fv(m_starProgram.getUniform(\"unColor\"), 1, &tColor[0]);\n    glUniform1f(m_starProgram.getUniform(\"unRadius\"), (f32)sCmp.radius);\n    f32v3 unCenterDir = glm::normalize(relCamPos);\n    glUniform3fv(m_starProgram.getUniform(\"unCenterDir\"), 1, &unCenterDir[0]);\n    // For logarithmic Z buffer\n    glUniform1f(m_starProgram.getUniform(\"unZCoef\"), zCoef);\n\n    // Bind VAO\n    glBindVertexArray(m_sVao);\n\n    glDrawElements(GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, 0);\n\n    glBindVertexArray(0);\n    m_starProgram.unuse();\n}\n\nvoid StarComponentRenderer::drawCorona(StarComponent& sCmp,\n                                       const f32m4& VP,\n                                       const f32m4& V,\n                                       const f32v3& relCamPos,\n                                       const f32 zCoef) {\n    f32v3 center(-relCamPos);\n    f32v3 camRight(V[0][0], V[1][0], V[2][0]);\n    f32v3 camUp(V[0][1], V[1][1], V[2][1]);\n\n    if (sCmp.visibility == 0.0f) return;\n\n    m_coronaProgram.use();\n\n    // Corona color\n    f32v3 tColor = getTempColorShift(sCmp);\n\n    // Upload uniforms\n    glUniform3fv(m_coronaProgram.getUniform(\"unCameraRight\"), 1, &camRight[0]);\n    glUniform3fv(m_coronaProgram.getUniform(\"unCameraUp\"), 1, &camUp[0]);\n    glUniform3fv(m_coronaProgram.getUniform(\"unCenter\"), 1, &center[0]);\n    glUniform3fv(m_coronaProgram.getUniform(\"unColor\"), 1, &tColor[0]);\n    // For logarithmic Z buffer\n    glUniform1f(m_coronaProgram.getUniform(\"unZCoef\"), zCoef);\n    // Size\n    glUniform1f(m_coronaProgram.getUniform(\"unMaxSize\"), 4.0f);\n    glUniform1f(m_coronaProgram.getUniform(\"unStarRadius\"), (f32)sCmp.radius);\n    // Time\n    static f64 dt = 0.0;\n    dt += 0.0001;\n    glUniform1f(m_coronaProgram.getUniform(\"unDT\"), (f32)dt);\n    glUniformMatrix4fv(m_coronaProgram.getUniform(\"unWVP\"), 1, GL_FALSE, &VP[0][0]);\n\n    // Bind VAO\n    glBindVertexArray(m_cVao);\n\n    glDepthMask(GL_FALSE);\n    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);\n    glDepthMask(GL_TRUE);\n\n    glBindVertexArray(0);\n    m_coronaProgram.unuse();\n}\n\nf32v3 hdrs(f32v3 v) {\n    return f32v3(1.0f) - glm::exp(v * -3.0f);\n}\n\nvoid StarComponentRenderer::drawGlow(const StarComponent& sCmp,\n                                     const f32m4& VP,\n                                     const f64v3& relCamPos,\n                                     float aspectRatio,\n                                     const f32v3& viewDirW,\n                                     const f32v3& viewRightW,\n                                     const f32v3& colorMult /* = f32v3(1.0f) */ ) {\n\n    if (sCmp.visibility == 0.0f) return;\n  \n    // Compute desired size based on distance and ratio of mass to Sol mass\n    f64 s = calculateGlowSize(sCmp, relCamPos) * sCmp.visibility;\n    // Don't render if its too small\n    if (s <= 0.0) return;\n\n    f32v2 dims(s, s * aspectRatio);\n   \n    m_glowProgram.use();\n\n    f32 scale = glm::clamp((f32)((sCmp.temperature - MIN_TMP) / TMP_RANGE), 0.0f, 1.0f);\n\n    // Upload uniforms\n    f32v3 center(-relCamPos);\n    glUniform3fv(m_glowProgram.getUniform(\"unCenter\"), 1, &center[0]);\n    glUniform3fv(m_glowProgram.getUniform(\"unColorMult\"), 1, &colorMult[0]);\n    glUniform1f(m_glowProgram.getUniform(\"unColorMapU\"), scale);\n    glUniform2fv(m_glowProgram.getUniform(\"unDims\"), 1, &dims[0]);\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D, m_glowColorMap);\n    // For sparkles\n    f32v3 vs = viewDirW - viewRightW;\n    glUniform1f(m_glowProgram.getUniform(\"unNoiseZ\"), (vs.x + vs.y - vs.z) * 0.125f);\n\n    glUniformMatrix4fv(m_glowProgram.getUniform(\"unVP\"), 1, GL_FALSE, &VP[0][0]);\n    // Bind VAO\n    glBindVertexArray(m_gVao);\n\n    glDisable(GL_DEPTH_TEST);\n    glDepthMask(GL_FALSE);\n    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);\n    glDepthMask(GL_TRUE);\n    glEnable(GL_DEPTH_TEST);\n\n    glBindVertexArray(0);\n    m_glowProgram.unuse();\n}\n\nvoid StarComponentRenderer::updateOcclusionQuery(StarComponent& sCmp,\n                                                 const f32 zCoef,\n                                                 const f32m4& VP,\n                                                 const f64v3& relCamPos) {\n    if (!m_occlusionProgram.isCreated()) {\n        m_occlusionProgram = vg::ShaderManager::createProgram(OCCLUSION_VERT_SRC, OCCLUSION_FRAG_SRC);\n        glGenVertexArrays(1, &m_oVao);\n        glBindVertexArray(m_oVao);\n        vg::GpuMemory::bindBuffer(m_cVbo, vg::BufferTarget::ARRAY_BUFFER);\n        vg::GpuMemory::bindBuffer(m_cIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n        m_occlusionProgram.enableVertexAttribArrays();\n        glVertexAttribPointer(m_occlusionProgram.getAttribute(\"vPosition\"), 2, GL_FLOAT, GL_FALSE, 0, 0);\n        glBindVertexArray(0);\n    }\n    if (sCmp.occlusionQuery[0] == 0) {\n        glGenQueries(2, sCmp.occlusionQuery);\n    } else {\n        int totalSamples = 0;\n        int passedSamples = 0;\n        glGetQueryObjectiv(sCmp.occlusionQuery[0], GL_QUERY_RESULT, &totalSamples);\n        glGetQueryObjectiv(sCmp.occlusionQuery[1], GL_QUERY_RESULT, &passedSamples);\n        if (passedSamples == 0) {\n            sCmp.visibility = 0.0f;\n        } else {\n            sCmp.visibility = (f32)passedSamples / (f32)totalSamples;\n        }\n    }\n    // Have to calculate on the CPU since we need 64 bit precision. Otherwise\n    // we get the \"phantom star\" bug.\n    f64v4 pos(-relCamPos, 1.0);\n    f64v4 gl_Position = f64m4(VP) * pos;\n    f64v3 centerScreenspace64(gl_Position.x / gl_Position.w,\n                              gl_Position.y / gl_Position.w,\n                              gl_Position.z / gl_Position.w);\n    if (gl_Position.z < 0.0) {\n        centerScreenspace64.x = -100.0f; // force it off screen\n    } else {\n        centerScreenspace64.z = log2(glm::max(1e-6, gl_Position.w + 1.0)) * zCoef - 1.0;\n        centerScreenspace64.z *= gl_Position.w;\n    }\n    f32v3 centerScreenspace(centerScreenspace64);\n\n    f64 s = calculateGlowSize(sCmp, relCamPos) / 128.0;\n    s = glm::max(0.005, s); // make sure it never gets too small\n\n    m_occlusionProgram.use();\n\n    // Upload uniforms\n    glUniform3fv(m_occlusionProgram.getUniform(\"unCenterScreenspace\"), 1, &centerScreenspace[0]);\n    glUniform1f(m_occlusionProgram.getUniform(\"unSize\"), (f32)s);\n\n    glBindVertexArray(m_oVao);\n\n    glDepthMask(GL_FALSE);\n    glBeginQuery(GL_SAMPLES_PASSED, sCmp.occlusionQuery[0]);\n    glDisable(GL_DEPTH_TEST);\n    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);\n    glEnable(GL_DEPTH_TEST);\n    glDepthFunc(GL_LEQUAL);\n    glEndQuery(GL_SAMPLES_PASSED);\n    glBeginQuery(GL_SAMPLES_PASSED, sCmp.occlusionQuery[1]);\n    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);\n    glEndQuery(GL_SAMPLES_PASSED);\n    glDepthMask(GL_TRUE);\n    glDepthFunc(GL_LESS);\n\n    glBindVertexArray(0);\n\n    m_occlusionProgram.unuse();\n}\n\nvoid StarComponentRenderer::dispose() {\n    disposeShaders();\n    disposeBuffers();\n    if (m_tempColorMap.data) {\n        vg::ImageIO().free(m_tempColorMap);\n        m_tempColorMap.data = nullptr;\n        m_tempColorMap.width = -1;\n    }\n}\n\nvoid StarComponentRenderer::disposeShaders() {\n    if (m_starProgram.isCreated()) m_starProgram.dispose();\n    if (m_coronaProgram.isCreated()) m_coronaProgram.dispose();\n    if (m_glowProgram.isCreated()) m_glowProgram.dispose();\n    if (m_occlusionProgram.isCreated()) {\n        m_occlusionProgram.dispose();\n        // Also destroy VAO since they are related\n        glDeleteVertexArrays(1, &m_oVao);\n        m_oVao = 0;\n    }\n    disposeBuffers();\n}\n\nvoid StarComponentRenderer::disposeBuffers() {\n    // Dispose buffers too for proper reload\n    if (m_sVbo) {\n        vg::GpuMemory::freeBuffer(m_sVbo);\n    }\n    if (m_sIbo) {\n        vg::GpuMemory::freeBuffer(m_sIbo);\n    }\n    if (m_sVao) {\n        glDeleteVertexArrays(1, &m_sVao);\n        m_sVao = 0;\n    }\n    if (m_cVbo) {\n        vg::GpuMemory::freeBuffer(m_cVbo);\n    }\n    if (m_cIbo) {\n        vg::GpuMemory::freeBuffer(m_cIbo);\n    }\n    if (m_cVao) {\n        glDeleteVertexArrays(1, &m_cVao);\n        m_cVao = 0;\n    }\n    if (m_gVao) {\n        glDeleteVertexArrays(1, &m_gVao);\n        m_gVao = 0;\n    }\n}\n\nvoid StarComponentRenderer::buildShaders() {\n    m_starProgram = ShaderLoader::createProgramFromFile(\"Shaders/Star/star.vert\",\n                                                        \"Shaders/Star/star.frag\");\n    m_starProgram.use();\n    unWVP = m_starProgram.getUniform(\"unWVP\");\n    unDT = m_starProgram.getUniform(\"unDT\");\n    m_starProgram.unuse();\n\n    m_coronaProgram = ShaderLoader::createProgramFromFile(\"Shaders/Star/corona.vert\",\n                                                          \"Shaders/Star/corona.frag\");\n\n    m_glowProgram = ShaderLoader::createProgramFromFile(\"Shaders/Star/glow.vert\",\n                                                          \"Shaders/Star/glow.frag\");\n    m_glowProgram.use();\n    glUniform1i(m_glowProgram.getUniform(\"unColorMap\"), 0);\n    m_glowProgram.unuse();\n}\n\nvoid StarComponentRenderer::buildMesh() {\n    // Build star mesh\n    std::vector<ui32> indices;\n    std::vector<f32v3> positions;\n\n    // TODO(Ben): Optimize with LOD for far viewing\n    vmesh::generateIcosphereMesh(ICOSPHERE_SUBDIVISIONS, indices, positions);\n    m_numIndices = indices.size();\n\n    glGenVertexArrays(1, &m_sVao);\n    glBindVertexArray(m_sVao);\n\n    vg::GpuMemory::createBuffer(m_sVbo);\n    vg::GpuMemory::createBuffer(m_sIbo);\n\n    vg::GpuMemory::bindBuffer(m_sVbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_sVbo, vg::BufferTarget::ARRAY_BUFFER, positions.size() * sizeof(f32v3),\n                                    positions.data(), vg::BufferUsageHint::STATIC_DRAW);\n\n    vg::GpuMemory::bindBuffer(m_sIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_sIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(ui32),\n                                    indices.data(), vg::BufferUsageHint::STATIC_DRAW);\n\n    m_starProgram.enableVertexAttribArrays();\n    glVertexAttribPointer(m_starProgram.getAttribute(\"vPosition\"), 3, GL_FLOAT, GL_FALSE, 0, 0);\n  \n    // Build corona and glow mesh\n    glGenVertexArrays(1, &m_cVao);\n    glBindVertexArray(m_cVao);\n\n    vg::GpuMemory::createBuffer(m_cVbo);\n    vg::GpuMemory::createBuffer(m_cIbo);\n\n    f32v2 cPositions[4] = {\n        f32v2(-1.0f, 1.0f),\n        f32v2(-1.0f, -1.0f),\n        f32v2(1.0f, -1.0f),\n        f32v2(1.0f, 1.0f)\n    };\n\n    ui16 cIndices[6] = { 0, 1, 2, 2, 3, 0 };\n\n    vg::GpuMemory::bindBuffer(m_cVbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_cVbo, vg::BufferTarget::ARRAY_BUFFER, sizeof(cPositions),\n                                    cPositions, vg::BufferUsageHint::STATIC_DRAW);\n\n    vg::GpuMemory::bindBuffer(m_cIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_cIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER, sizeof(cIndices),\n                                    cIndices, vg::BufferUsageHint::STATIC_DRAW);\n\n    m_coronaProgram.enableVertexAttribArrays();\n    glVertexAttribPointer(m_coronaProgram.getAttribute(\"vPosition\"), 2, GL_FLOAT, GL_FALSE, 0, 0);\n\n    // Build glow VAO\n    glGenVertexArrays(1, &m_gVao);\n    glBindVertexArray(m_gVao);\n\n    vg::GpuMemory::bindBuffer(m_cVbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::bindBuffer(m_cIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n\n    m_glowProgram.enableVertexAttribArrays();\n    glVertexAttribPointer(m_glowProgram.getAttribute(\"vPosition\"), 2, GL_FLOAT, GL_FALSE, 0, 0);\n\n    glBindVertexArray(0);\n}\n\nvoid StarComponentRenderer::loadTempColorMap() {\n    // Load all the bitmap data\n    vio::Path path;\n    m_textureResolver->resolvePath(\"Sky/Star/star_spectrum_1.png\", path);\n    m_tempColorMap = vg::ImageIO().load(path);\n    if (!m_tempColorMap.data) {\n        fprintf(stderr, \"ERROR: Failed to load Sky/Star/star_spectrum_1.png\\n\");\n    }\n    m_textureResolver->resolvePath(\"Sky/Star/star_spectrum_2.png\", path);\n    vg::ScopedBitmapResource res2(vg::ImageIO().load(path));\n    if (!res2.data) {\n        fprintf(stderr, \"ERROR: Failed to load Sky/Star/star_spectrum_2.png\\n\");\n    }\n    m_textureResolver->resolvePath(\"Sky/Star/star_spectrum_3.png\", path);\n    vg::ScopedBitmapResource res3(vg::ImageIO().load(path));\n    if (!res3.data) {\n        fprintf(stderr, \"ERROR: Failed to load Sky/Star/star_spectrum_3.png\\n\");\n    }\n\n    // Error check dimensions\n    if ((m_tempColorMap.width != res2.width) || (res2.width != res3.width) ||\n        (m_tempColorMap.height != res2.height) || (res2.height != res3.height)) {\n        pError(\"star_spectrum images should all be the same dimensions!\");\n    }\n\n    // Create the texture array\n    if (m_glowColorMap == 0) glGenTextures(1, &m_glowColorMap);\n    glBindTexture(GL_TEXTURE_2D, m_glowColorMap);\n\n    // Set up storage\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_tempColorMap.width, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);\n     \n    // Upload the data to VRAM\n    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_tempColorMap.width, m_tempColorMap.height, GL_RGBA, GL_UNSIGNED_BYTE, m_tempColorMap.data);\n    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 1, res2.width, res2.height, GL_RGBA, GL_UNSIGNED_BYTE, res2.data);\n    // Copy res3 twice so we get PO2 texture\n    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 2, res3.width, res3.height, GL_RGBA, GL_UNSIGNED_BYTE, res3.data);\n    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 3, res3.width, res3.height, GL_RGBA, GL_UNSIGNED_BYTE, res3.data);\n  \n    // Set up tex parameters\n    vg::SamplerState::LINEAR_CLAMP.set(GL_TEXTURE_2D);\n    // No mipmapping\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0);\n    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);\n\n    // Unbind\n    glBindTexture(GL_TEXTURE_2D, 0);\n\n    // Check if we had any errors\n    checkGlError(\"StarComponentRenderer::loadTempColorMap()\");\n}\n\nvoid StarComponentRenderer::loadGlowTextures() {\n    // TODO(Ben): remove this\n    /*vio::Path path;\n    m_textureResolver->resolvePath(\"Sky/Star/star_glow_overlay.png\", path);\n    vg::ScopedBitmapResource rs2 = vg::ImageIO().load(path);\n    if (!m_tempColorMap.data) {\n    fprintf(stderr, \"ERROR: Failed to load Sky/Star/star_glow_overlay.png\\n\");\n    } else {\n    m_glowTexture = vg::GpuMemory::uploadTexture(&rs2);\n    }*/\n}\n\nf64 StarComponentRenderer::calculateGlowSize(const StarComponent& sCmp, const f64v3& relCamPos) {\n    static const f64 DSUN = 1392684.0;\n    static const f64 TSUN = 5778.0;\n\n    // Georg's magic formula\n    f64 d = glm::length(relCamPos); // Distance\n    f64 D = sCmp.radius * 2.0 * DSUN;\n    f64 L = (D * D) * pow(sCmp.temperature / TSUN, 4.0); // Luminosity\n    return 0.016 * pow(L, 0.25) / pow(d, 0.5); // Size\n}\n\nf32v3 StarComponentRenderer::calculateStarColor(const StarComponent& sCmp) {\n    // Calculate temperature color\n    f32v3 tColor;\n    f32 scale = (f32)(m_tempColorMap.width * (sCmp.temperature - MIN_TMP) / TMP_RANGE);\n    scale = glm::clamp(scale, 0.0f, (f32)m_tempColorMap.width);\n    ui32 rScale = (ui32)(scale + 0.5f);\n    ui32 iScale = (ui32)scale;\n\n    if (rScale >= m_tempColorMap.width) rScale = m_tempColorMap.width - 1;\n\n    if (iScale < rScale) { // Interpolate down\n        if (iScale == 0) {\n            tColor = getColor(iScale);\n        } else {\n            tColor = lerp(getColor(iScale), getColor(rScale), scale - (f32)iScale);\n        }\n    } else { // Interpolate up\n        if (rScale >= m_tempColorMap.width-1) {\n            tColor = getColor((int)m_tempColorMap.width - 1);\n        } else {\n            tColor = lerp(getColor(rScale), getColor(rScale + 1), scale - (f32)rScale);\n        }\n    }\n    \n    return tColor;\n}\n\nf32v3 StarComponentRenderer::getColor(int index) {\n    const ui8v4& bytes = m_tempColorMap.bytesUI8v4[index];\n    return f32v3(bytes.r / 255.0f, bytes.g / 255.0f, bytes.b / 255.0f);\n}\n\nf32v3 StarComponentRenderer::getTempColorShift(const StarComponent& sCmp) {\n    return f32v3(sCmp.temperature * (0.0534 / 255.0) - (43.0 / 255.0),\n                 sCmp.temperature * (0.0628 / 255.0) - (77.0 / 255.0),\n                 sCmp.temperature * (0.0735 / 255.0) - (115.0 / 255.0));\n\n}\n"
  },
  {
    "path": "SoA/StarComponentRenderer.h",
    "content": "///\n/// StarComponentRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 9 Apr 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Renderer for StarComponents\n///\n\n#pragma once\n\n#ifndef StarComponentRenderer_h__\n#define StarComponentRenderer_h__\n\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/ecs/ComponentTable.hpp>\n#include <Vorb/ecs/ECS.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/graphics/gtypes.h>\n\nclass ModPathResolver;\n\nstruct StarComponent;\n\nclass StarComponentRenderer {\npublic:\n    StarComponentRenderer();\n    ~StarComponentRenderer();\n\n    void init(const ModPathResolver* textureResolver);\n    void initGL();\n\n    void drawStar(const StarComponent& sCmp,\n                  const f32m4& VP,\n                  const f64q& orientation,\n                  const f32v3& relCamPos,\n                  const f32 zCoef);\n    void drawCorona(StarComponent& sCmp,\n                    const f32m4& VP,\n                    const f32m4& V,\n                    const f32v3& relCamPos,\n                    const f32 zCoef);\n    void drawGlow(const StarComponent& sCmp,\n                  const f32m4& VP,\n                  const f64v3& relCamPos,\n                  float aspectRatio,\n                  const f32v3& viewDirW,\n                  const f32v3& viewRightW,\n                  const f32v3& colorMult = f32v3(1.0f));\n    void updateOcclusionQuery(StarComponent& sCmp,\n                              const f32 zCoef,\n                              const f32m4& VP,\n                              const f64v3& relCamPos);\n\n    void dispose();\n    void disposeShaders();\n    void disposeBuffers();\n\n    f32v3 calculateStarColor(const StarComponent& sCmp);\n    f64 calculateGlowSize(const StarComponent& sCmp, const f64v3& relCamPos);\n\nprivate:\n    void buildShaders();\n    void buildMesh();\n    void loadTempColorMap();\n    void loadGlowTextures();\n    f32v3 getColor(int index);\n    f32v3 getTempColorShift(const StarComponent& sCmp);\n\n    vg::GLProgram m_starProgram;\n    vg::GLProgram m_coronaProgram;\n    vg::GLProgram m_glowProgram;\n    vg::GLProgram m_occlusionProgram;\n    // Star\n    VGBuffer m_sVbo = 0;\n    VGIndexBuffer m_sIbo = 0;\n    VGVertexArray m_sVao = 0;\n    // Corona\n    VGBuffer m_cVbo = 0;\n    VGIndexBuffer m_cIbo = 0;\n    VGVertexArray m_cVao = 0;\n    // Glow\n    VGVertexArray m_gVao = 0;\n    // Occlusion\n    VGVertexArray m_oVao = 0;\n    \n    vg::BitmapResource m_tempColorMap;\n    VGTexture m_glowColorMap = 0;\n    int m_numIndices = 0;\n\n    // TODO(Ben): UBO\n    VGUniform unWVP;\n    VGUniform unDT;\n\n    const ModPathResolver* m_textureResolver = nullptr;\n};\n\n#endif // StarComponentRenderer_h__\n"
  },
  {
    "path": "SoA/Startup.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Startup.h\"\n\nnamespace {\n    void printHelp() {\n        printf(R\"(\n\nCommand-line arguments:\n\"-a\" to launch main application\n\"-c\" to bring up the console\n\"-h\" for this help text\n\"-q\" to do nothing\n\n... Press any key to exit ...\n)\");\n    }\n}\n\nStartup startup(int argc, cString* argv) {\n    // Application mode is the default\n    Startup mode = Startup::HELP;\n    bool shouldOutputHelp = false;\n\n    // Check if another argument exists\n    if (argc > 1) {\n        for (int i = 1; i < argc; i++) {\n            if (strcmp(argv[i], \"-a\") == 0) {\n                mode = Startup::APP;\n            } else if (strcmp(argv[i], \"-c\") == 0) {\n                mode = Startup::CONSOLE;\n            } else if (strcmp(argv[i], \"-help\") == 0 || strcmp(argv[i], \"-h\") == 0) {\n                shouldOutputHelp = true;\n                break;\n            } else if (strcmp(argv[i], \"-q\") == 0) {\n                mode = Startup::EXIT;\n            } else {\n                printf(\"Unrecognized option:\\n%s\\n\", argv[i]);\n            }\n        }\n    }\n\n    // Print help if they wanted it or didn't enter anything meaningful\n    if (shouldOutputHelp || mode == Startup::HELP) {\n        printHelp();\n    }\n\n    return mode;\n}\n"
  },
  {
    "path": "SoA/Startup.h",
    "content": "//\n// Startup.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 29 Jun 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef Startup_h__\n#define Startup_h__\n\n#include \"Vorb/types.h\"\n\n/*! @brief Designates the startup format.\n */\nenum class Startup {\n    APP,\n    CONSOLE,\n    HELP,\n    EXIT\n};\n\n/*! @brief Determines how to startup the application from its arguments.\n * \n * @param argc: Number of process arguments.\n * @param argv: Values of process arguments.\n * @return The way to start the application.\n */\nStartup startup(int argc, cString* argv);\n\n#endif // Startup_h__\n"
  },
  {
    "path": "SoA/SystemARRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SystemARRenderer.h\"\n\n#include \"Camera.h\"\n#include \"MainMenuSystemViewer.h\"\n#include \"ModPathResolver.h\"\n#include \"ShaderLoader.h\"\n#include \"SpaceSystem.h\"\n#include \"soaUtils.h\"\n\n#include <Vorb/colors.h>\n#include <Vorb/graphics/DepthState.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/SamplerState.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/utils.h>\n\nnamespace {\n    const cString VERT_SRC = R\"(\nuniform mat4 unWVP;\nin vec4 vPosition;\nin float vAngle;\nout float fAngle;\n#include \"Shaders/Utils/logz.glsl\"\nvoid main() {\n    fAngle = vAngle;\n    gl_Position = unWVP * vPosition;\n    applyLogZ();\n}\n)\";\n\n    const cString FRAG_SRC = R\"(\nuniform vec4 unColor;\nuniform float currentAngle;\nin float fAngle;\nout vec4 pColor;\nvoid main() {\n    pColor = unColor * vec4(1.0, 1.0, 1.0, 1.0 - mod(fAngle + currentAngle, 1.0));\n}\n)\";\n}\n\nSystemARRenderer::SystemARRenderer() {\n    // Empty\n}\n\nSystemARRenderer::~SystemARRenderer() {\n    dispose();\n}\n\nvoid SystemARRenderer::init(const ModPathResolver* textureResolver) {\n    m_textureResolver = textureResolver;\n}\n\nvoid SystemARRenderer::initGL() {\n    if (!m_colorProgram.isCreated()) m_colorProgram = ShaderLoader::createProgram(\"SystemAR\", VERT_SRC, FRAG_SRC);\n    if (m_selectorTexture == 0) loadTextures();\n}\n\nvoid SystemARRenderer::draw(SpaceSystem* spaceSystem, const Camera* camera,\n                            OPT const MainMenuSystemViewer* systemViewer,\n                            const f32v2& viewport) {\n    // Get handles so we don't have huge parameter lists\n    m_spaceSystem = spaceSystem;\n    m_camera = camera;\n    m_systemViewer = systemViewer;\n    m_viewport = viewport;\n    m_zCoef = computeZCoef(camera->getFarClip());\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE);\n    glDepthMask(GL_FALSE);\n    glDepthFunc(GL_LEQUAL);\n    drawPaths();\n    if (m_systemViewer) {\n        drawHUD();\n    }\n    glDepthMask(GL_TRUE);\n    glDepthFunc(GL_LESS);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n}\n\nvoid SystemARRenderer::dispose() {\n    if (m_colorProgram.isCreated()) {\n        m_colorProgram.dispose();\n    }\n  \n    if (m_spriteBatch) {\n        m_spriteBatch->dispose();\n        m_spriteFont->dispose();\n        delete m_spriteBatch;\n        m_spriteBatch = nullptr;\n        delete m_spriteFont;\n        m_spriteFont = nullptr;\n    }\n}\n\nvoid SystemARRenderer::loadTextures() {\n    { // Selector\n        vio::Path path;\n        m_textureResolver->resolvePath(\"GUI/selector.png\", path);\n        vg::ScopedBitmapResource res(vg::ImageIO().load(path));\n        if (!res.data) {\n            fprintf(stderr, \"ERROR: Failed to load GUI/selector.png\\n\");\n        }\n        m_selectorTexture = vg::GpuMemory::uploadTexture(&res, vg::TexturePixelType::UNSIGNED_BYTE,\n                                                     vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_CLAMP_MIPMAP);\n    }\n    { // Barycenter\n        vio::Path path;\n        m_textureResolver->resolvePath(\"GUI/barycenter.png\", path);\n        vg::ScopedBitmapResource res(vg::ImageIO().load(path));\n        if (!res.data) {\n            fprintf(stderr, \"ERROR: Failed to load GUI/barycenter.png\\n\");\n        }\n        m_baryTexture = vg::GpuMemory::uploadTexture(&res, vg::TexturePixelType::UNSIGNED_BYTE,\n                                                     vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_CLAMP_MIPMAP);\n    }\n}\n\nvoid SystemARRenderer::drawPaths() {\n\n    float blendFactor;\n\n    // Draw paths\n    m_colorProgram.use();\n    m_colorProgram.enableVertexAttribArrays();\n\n    // For logarithmic Z buffer\n    glUniform1f(m_colorProgram.getUniform(\"unZCoef\"), m_zCoef);\n    glLineWidth(3.0f);\n\n    f32m4 wvp = m_camera->getProjectionMatrix() * m_camera->getViewMatrix();\n    for (auto& it : m_spaceSystem->orbit) {\n        auto& cmp = it.second;\n    \n        bool isSelected = false;\n        f32v4 oldPathColor; // To cache path color since we force it to a different one\n        if (m_systemViewer) {\n            // Get the augmented reality data\n            const MainMenuSystemViewer::BodyArData* bodyArData = m_systemViewer->finBodyAr(it.first);\n            if (bodyArData == nullptr) continue;\n\n            // ui8v3 ui8Color;\n            // If its selected we force a different color\n            if (m_systemViewer->getTargetBody() == it.first) {\n                isSelected = true;\n                oldPathColor = cmp.pathColor[0];\n                cmp.pathColor[0] = m_spaceSystem->pathColorMap[\"Selected\"].second;\n                blendFactor = 0.0;\n            } else {\n                // Hermite interpolated alpha\n                blendFactor = hermite(bodyArData->hoverTime);\n            }\n        } else {\n            blendFactor = 0.0;\n        }\n\n        if (cmp.parentOrbId) {\n            OrbitComponent& pOrbCmp = m_spaceSystem->orbit.get(cmp.parentOrbId);\n            m_orbitComponentRenderer.drawPath(cmp, m_colorProgram, wvp, &m_spaceSystem->namePosition.getFromEntity(it.first),\n                                              m_camera->getPosition(), blendFactor, &m_spaceSystem->namePosition.get(pOrbCmp.npID));\n        } else {\n            m_orbitComponentRenderer.drawPath(cmp, m_colorProgram, wvp, &m_spaceSystem->namePosition.getFromEntity(it.first),\n                                              m_camera->getPosition(), blendFactor);\n        }\n\n        // Restore path color\n        if (isSelected) cmp.pathColor[0] = oldPathColor;\n    }\n    m_colorProgram.disableVertexAttribArrays();\n    m_colorProgram.unuse();\n}\n\nvoid SystemARRenderer::drawHUD() {\n    const f32 ROTATION_FACTOR = (f32)(M_PI + M_PI / 4.0);\n    static f32 dt = 0.0;\n    dt += 0.01f;\n\n    // Lazily load spritebatch\n    if (!m_spriteBatch) {\n        m_spriteBatch = new vg::SpriteBatch(true, true);\n        m_spriteFont = new vg::SpriteFont();\n        m_spriteFont->init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n    }\n\n    m_spriteBatch->begin();\n\n    // Render all bodies\n    for (auto& it : m_spaceSystem->orbit) {\n\n        auto& oCmp = it.second;\n        auto& npCmp = m_spaceSystem->namePosition.get(oCmp.npID);\n\n        // Get the augmented reality data\n        const MainMenuSystemViewer::BodyArData* bodyArData = m_systemViewer->finBodyAr(it.first);\n        if (bodyArData == nullptr) continue;\n\n        if (bodyArData->inFrustum) {\n\n            f64v3 position = npCmp.position;\n            f64v3 relativePos = position - m_camera->getPosition();\n            f64 distance = glm::length(relativePos);\n            color4 textColor;\n\n            f32 hoverTime = bodyArData->hoverTime;\n\n            // Get screen position \n            f32v3 screenCoords = m_camera->worldToScreenPointLogZ(relativePos, (f64)m_camera->getFarClip());\n            f32v2 xyScreenCoords(screenCoords.x * m_viewport.x, screenCoords.y * m_viewport.y);\n\n            // Get a smooth interpolator with hermite\n            f32 interpolator = hermite(hoverTime);\n\n            // Calculate colors\n            ui8v3 ui8Color;\n            // If its selected we use a different color\n            bool isSelected = false;\n            if (m_systemViewer->getTargetBody() == it.first) {\n                isSelected = true;\n                ui8Color = ui8v3(m_spaceSystem->pathColorMap[\"Selected\"].second * 255.0f);\n            } else {\n                ui8Color = ui8v3(lerp(oCmp.pathColor[0], oCmp.pathColor[1], interpolator) * 255.0f);\n            }\n            color4 oColor(ui8Color.r, ui8Color.g, ui8Color.b, 255u);\n            textColor.lerp(color::LightGray, color::White, interpolator);\n\n            f32 selectorSize = bodyArData->selectorSize;\n\n            // Only render if it isn't too big\n            if (selectorSize < MainMenuSystemViewer::MAX_SELECTOR_SIZE) {\n\n                // Alpha interpolation from size so they fade out\n                f32 low = MainMenuSystemViewer::MAX_SELECTOR_SIZE * 0.7f;\n                if (selectorSize > low) {\n                    // Fade out when close\n                    oColor.a = (ui8)((1.0f - (selectorSize - low) /\n                        (MainMenuSystemViewer::MAX_SELECTOR_SIZE - low)) * 255);\n                    textColor.a = oColor.a;\n                } else {\n                    f64 d = distance - (f64)low;\n                    // Fade name based on distance\n                    switch (oCmp.type) {\n                        case SpaceObjectType::STAR:\n                            textColor.a = oColor.a = (ui8)(glm::max(0.0, (f64)textColor.a - d * 0.00000000001));\n                            break;\n                        case SpaceObjectType::BARYCENTER:\n                        case SpaceObjectType::PLANET:\n                        case SpaceObjectType::DWARF_PLANET:\n                            textColor.a = oColor.a = (ui8)(glm::max(0.0, (f64)textColor.a - d * 0.000000001));\n                            break;\n                        default:\n                            textColor.a = oColor.a = (ui8)(glm::max(0.0, (f64)textColor.a - d * 0.000001));\n                            break;\n                    }\n                }\n\n                // Pick texture\n                VGTexture tx;\n                if (oCmp.type == SpaceObjectType::BARYCENTER) {\n                    tx = m_baryTexture;\n                    selectorSize = MainMenuSystemViewer::MIN_SELECTOR_SIZE * 2.5f - (f32)(distance * 0.00000000001);\n                    if (selectorSize < 0.0) continue;        \n                    interpolator = 0.0f; // Don't rotate barycenters\n                } else {\n                    tx = m_selectorTexture;\n                }\n\n                // Draw Indicator\n                m_spriteBatch->draw(tx, nullptr, nullptr,\n                                    xyScreenCoords,\n                                    f32v2(0.5f, 0.5f),\n                                    f32v2(selectorSize),\n                                    interpolator * ROTATION_FACTOR,\n                                    oColor, screenCoords.z);\n\n                // Text offset and scaling\n                const f32v2 textOffset(selectorSize / 2.0f, -selectorSize / 2.0f);\n                const f32v2 textScale((((selectorSize - MainMenuSystemViewer::MIN_SELECTOR_SIZE) /\n                    (MainMenuSystemViewer::MAX_SELECTOR_SIZE - MainMenuSystemViewer::MIN_SELECTOR_SIZE)) * 0.5f + 0.5f) * 0.6f);\n\n                // Draw Text\n                if (textColor.a > 0) {\n                    m_spriteBatch->drawString(m_spriteFont,\n                                              npCmp.name.c_str(),\n                                              xyScreenCoords + textOffset,\n                                              textScale,\n                                              textColor,\n                                              vg::TextAlign::TOP_LEFT,\n                                              screenCoords.z);\n                }\n\n            }\n            // Land selector\n            if (isSelected && bodyArData->isLandSelected) {\n                f32v3 selectedPos = bodyArData->selectedPos;\n                // Apply axis rotation if applicable\n                vecs::ComponentID componentID = m_spaceSystem->axisRotation.getComponentID(it.first);\n                if (componentID) {\n                    f64q rot = m_spaceSystem->axisRotation.get(componentID).currentOrientation;\n                    selectedPos = f32v3(rot * f64v3(selectedPos));\n                }\n\n                relativePos = (position + f64v3(selectedPos)) - m_camera->getPosition();\n                // Bring it close to the camera so it doesn't get occluded by anything\n                relativePos = glm::normalize(relativePos) * ((f64)m_camera->getNearClip() + 0.0001);\n                screenCoords = m_camera->worldToScreenPointLogZ(relativePos, (f64)m_camera->getFarClip());\n                xyScreenCoords = f32v2(screenCoords.x * m_viewport.x, screenCoords.y * m_viewport.y);\n\n                color4 sColor = color::Red;\n                sColor.a = 155;\n                m_spriteBatch->draw(m_selectorTexture, nullptr, nullptr,\n                                    xyScreenCoords,\n                                    f32v2(0.5f, 0.5f),\n                                    f32v2(22.0f) + (cosf(dt * 8.0f) * 4.0f),\n                                    dt * ROTATION_FACTOR,\n                                    sColor, screenCoords.z);\n            }\n        }\n    }\n\n    m_spriteBatch->end();\n    m_spriteBatch->render(m_viewport, nullptr, &vg::DepthState::READ, nullptr);\n}\n"
  },
  {
    "path": "SoA/SystemARRenderer.h",
    "content": "///\n/// SystemARRenderer.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 22 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Augmented reality renderer for Space Systems\n///\n\n#pragma once\n\n#ifndef SystemARRenderer_h__\n#define SystemARRenderer_h__\n\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/VorbPreDecl.inl>\n#include \"OrbitComponentRenderer.h\"\n#include <Vorb/graphics/GLProgram.h>\n\nclass Camera;\nclass MainMenuSystemViewer;\nclass SpaceSystem;\nclass ModPathResolver;\n\nDECL_VG(class SpriteBatch;\n        class SpriteFont)\n\nclass SystemARRenderer {\npublic:\n    SystemARRenderer();\n    ~SystemARRenderer();\n\n    void init(const ModPathResolver* textureResolver);\n    void initGL();\n\n    void draw(SpaceSystem* spaceSystem, const Camera* camera,\n              OPT const MainMenuSystemViewer* systemViewer,\n              const f32v2& viewport);\n\n    void dispose();\n\nprivate:\n    void loadTextures();\n    // Renders space paths\n    void drawPaths();\n    // Renders heads up display\n    void drawHUD();\n\n    vg::GLProgram m_colorProgram;\n    vg::SpriteBatch* m_spriteBatch = nullptr;\n    vg::SpriteFont* m_spriteFont = nullptr;\n\n    // Helper variables to avoid passing\n    const ModPathResolver* m_textureResolver = nullptr;\n    SpaceSystem* m_spaceSystem = nullptr;\n    const Camera* m_camera = nullptr;\n    const MainMenuSystemViewer* m_systemViewer = nullptr;\n    VGTexture m_selectorTexture = 0;\n    VGTexture m_baryTexture = 0;\n    f32v2 m_viewport;\n    f32 m_zCoef;\n\n    OrbitComponentRenderer m_orbitComponentRenderer;\n};\n\n#endif // SystemARRenderer_h__\n"
  },
  {
    "path": "SoA/SystemBodyLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SystemBodyLoader.h\"\n\n#include \"SpaceSystemAssemblages.h\"\n#include \"SoAState.h\"\n\n#include <Vorb/io/IOManager.h>\n\nvoid SystemBodyLoader::init(vio::IOManager* iom) {\n    m_iom = iom;\n    m_planetLoader.init(iom);\n}\n\n// TODO: Check why glrpc is currently unused.\nbool SystemBodyLoader::loadBody(const SoaState* soaState, const nString& filePath,\n                                const SystemOrbitProperties* sysProps, SystemBody* body, keg::Node &value,\n                                vcore::RPCManager* glrpc VORB_UNUSED /* = nullptr */) {\n\n#define KEG_CHECK \\\n    if (error != keg::Error::NONE) { \\\n        fprintf(stderr, \"keg error %d for %s\\n\", (int)error, filePath.c_str()); \\\n        goodParse = false; \\\n        return;  \\\n                    }\n\n    keg::Error error;\n    nString data;\n    nString propertiesFile=filePath+\"properties.yml\";\n\n    m_iom->readFileToString(propertiesFile.c_str(), data);\n\n    keg::ReadContext context;\n    context.env=keg::getGlobalEnvironment();\n\n    bool goodParse = true;\n    bool foundOne = false;\n    auto f = makeFunctor([&](Sender, const nString& type, keg::Node value) {\n        if (foundOne) return;\n\n        // Parse based on type\n        if (type == \"planet\") {\n            PlanetProperties properties;\n            error = keg::parse((ui8*)&properties, value, context, &KEG_GLOBAL_TYPE(PlanetProperties));\n            KEG_CHECK;\n\n            // Use planet loader to load terrain and biomes\n            if (properties.generation.length()) {\n                properties.planetGenData = m_planetLoader.loadPlanetGenData(properties.generation);\n            } else {\n                properties.planetGenData = nullptr;\n                // properties.planetGenData = pr.planetLoader->getRandomGenData(properties.density, pr.glrpc);\n                properties.atmosphere = m_planetLoader.getRandomAtmosphere();\n            }\n\n            // Set the radius for use later\n            if (properties.planetGenData) {\n                properties.planetGenData->radius = properties.diameter / 2.0;\n            }\n\n            SpaceSystemAssemblages::createPlanet(soaState->spaceSystem, sysProps, &properties, body, soaState->threadPool);\n            body->type = SpaceBodyType::PLANET;\n        } else if (type == \"star\") {\n            StarProperties properties;\n            error = keg::parse((ui8*)&properties, value, context, &KEG_GLOBAL_TYPE(StarProperties));\n            KEG_CHECK;\n            SpaceSystemAssemblages::createStar(soaState->spaceSystem, sysProps, &properties, body);\n            body->type = SpaceBodyType::STAR;\n        } else if (type == \"gasGiant\") {\n            GasGiantProperties properties;\n            error = keg::parse((ui8*)&properties, value, context, &KEG_GLOBAL_TYPE(GasGiantProperties));\n            KEG_CHECK;\n            // Get full path for color map\n            if (properties.colorMap.size()) {\n                vio::Path colorPath;\n                if (!m_iom->resolvePath(properties.colorMap, colorPath)) {\n                    fprintf(stderr, \"Failed to resolve %s\\n\", properties.colorMap.c_str());\n                }\n                properties.colorMap = colorPath.getString();\n            }\n            // Get full path for rings\n            if (properties.rings.size()) {\n                for (size_t i = 0; i < properties.rings.size(); i++) {\n                    auto& r = properties.rings[i];\n                    // Resolve the path\n                    vio::Path ringPath;\n                    if (!m_iom->resolvePath(r.colorLookup, ringPath)) {\n                        fprintf(stderr, \"Failed to resolve %s\\n\", r.colorLookup.c_str());\n                    }\n                    r.colorLookup = ringPath.getString();\n                }\n            }\n            // Create the component\n            SpaceSystemAssemblages::createGasGiant(soaState->spaceSystem, sysProps, &properties, body);\n            body->type = SpaceBodyType::GAS_GIANT;\n        }\n\n        //Only parse the first\n        foundOne = true;\n    });\n\n    if(data.empty())\n    {\n        f.invoke(nullptr, spaceObjectTypeName(sysProps->type), value);\n    }\n    else\n    {\n        context.reader.init(data.c_str());\n        keg::Node node=context.reader.getFirst();\n\n        if(keg::getType(node)!=keg::NodeType::MAP)\n        {\n            //lets go ahead and give it an entity id even though we dont have properties for it\n            body->entity=soaState->spaceSystem->addEntity();\n\n            std::cout<<\"Failed to load \"+filePath;\n            context.reader.dispose();\n            return false;\n        }\n\n        context.reader.forAllInMap(node, &f);\n    }\n\n    context.reader.dispose();\n\n    return goodParse;\n}\n"
  },
  {
    "path": "SoA/SystemBodyLoader.h",
    "content": "///\n/// SystemBodyLoader.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 12 Jul 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Loads a system body\n///\n\n#pragma once\n\n#ifndef SystemBodyLoader_h__\n#define SystemBodyLoader_h__\n\n#include \"PlanetGenLoader.h\"\n\n#include <Vorb/VorbPreDecl.inl>\n\nstruct SoaState;\nDECL_VIO(class IOManager);\n\nclass SystemBodyLoader {\npublic:\n    void init(vio::IOManager* iom);\n\n    bool loadBody(const SoaState* soaState, const nString& filePath,\n                                    const SystemOrbitProperties* sysProps, SystemBody* body, keg::Node &value,\n                                    vcore::RPCManager* glrpc = nullptr);\n\nprivate:\n    vio::IOManager* m_iom;\n    PlanetGenLoader m_planetLoader;\n};\n\n#endif // SystemBodyLoader_h__\n"
  },
  {
    "path": "SoA/TerrainGenTextures.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TerrainGenTextures.h\"\n#include \"Errors.h\"\n\n#include <Vorb/graphics/SamplerState.h>\n#include <Vorb/graphics/GpuMemory.h>\n\nTerrainGenTextures::~TerrainGenTextures() {\n    destroy();\n}\n\nvoid TerrainGenTextures::init(const ui32v2& dims) {\n    m_dims = dims;\n\n    glGenFramebuffers(1, &m_fbo);\n    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);\n\n    // Create texture targets\n    glGenTextures(1, m_textures);\n    initTarget(m_dims, m_tex.height_temp_hum, TERRAINGEN_INTERNAL_FORMAT, 0);\n   \n    // Set the output location for pixels\n    VGEnum bufs[1] = {\n        GL_COLOR_ATTACHMENT0\n    };\n    glDrawBuffers(1, bufs);\n\n    // Unbind used resources\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n\n    // TODO: Change The Memory Usage Of The GPU\n}\n\nvoid TerrainGenTextures::use() {\n    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);\n    glViewport(0, 0, m_dims.x, m_dims.y);\n}\n\nvoid TerrainGenTextures::unuse() {\n    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n}\n\nvoid TerrainGenTextures::destroy() {\n    if (m_fbo != 0) {\n        glDeleteFramebuffers(1, &m_fbo);\n        m_fbo = 0;\n    }\n    if (m_tex.height_temp_hum != 0) {\n        glDeleteTextures(1, m_textures);\n        m_tex = { 0 };\n    }\n}\n\nvoid TerrainGenTextures::initTarget(const ui32v2& size, const ui32& texID, const vg::TextureInternalFormat& format, const ui32& attachment) {\n    glBindTexture(GL_TEXTURE_2D, texID);\n    glTexImage2D(GL_TEXTURE_2D, 0, (VGEnum)format, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);\n    vg::SamplerState::POINT_CLAMP.set(GL_TEXTURE_2D);\n    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachment, GL_TEXTURE_2D, texID, 0);\n}"
  },
  {
    "path": "SoA/TerrainGenTextures.h",
    "content": "///\n/// TerrainGenTextures.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 18 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// The output textures for terrain generation\n///\n\n#pragma once\n\n#ifndef TerrainGenTextures_h__\n#define TerrainGenTextures_h__\n\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/graphics/GLEnums.h>\n\n#define TERRAINGEN_INTERNAL_FORMAT vg::TextureInternalFormat::RGBA32F\n\nclass TerrainGenTextures {\npublic:\n    struct TextureIDs {\n    public:\n        VGTexture height_temp_hum;\n    };\n\n    ~TerrainGenTextures();\n\n    void init(const ui32v2& dims);\n\n    /// @return OpenGL texture IDs\n    const TerrainGenTextures::TextureIDs& getTextureIDs() const {\n        return m_tex;\n    }\n\n    void use();\n    \n    static void unuse();\n\n    void destroy();\nprivate:\n    void initTarget(const ui32v2& size, const ui32& texID, const vg::TextureInternalFormat& format, const ui32& attachment);\n   \n    union {\n        TextureIDs m_tex; ///< Named texture targets\n        VGTexture m_textures[1]; ///< All 1 textures\n    };\n\n    VGFramebuffer m_fbo = 0;\n    ui32v2 m_dims = ui32v2(0);\n};\n\n#endif // TerrainGenTextures_h__"
  },
  {
    "path": "SoA/TerrainPatch.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TerrainPatch.h\"\n#include \"TerrainPatchMesher.h\"\n#include \"TerrainPatchMesh.h\"\n\n#include \"Chunk.h\"\n#include <Vorb/vorb_rpc.h>\n#include \"RenderUtils.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"SphericalTerrainComponentUpdater.h\"\n#include \"TerrainPatchMeshTask.h\"\n#include \"VoxPool.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"VoxelSpaceConversions.h\"\n#include \"soaUtils.h\"\n\nf32 TerrainPatch::DIST_MIN = 1.0f;\nf32 TerrainPatch::DIST_MAX = 1.1f;\nf32 TerrainPatch::MIN_SIZE = 0.4096f;\nint TerrainPatch::PATCH_MAX_LOD = 25;\n\nTerrainPatch::~TerrainPatch() {\n    destroy();\n}\n\nvoid TerrainPatch::init(const f64v2& gridPosition,\n                                 WorldCubeFace cubeFace,\n                                 int lod,\n                                 const TerrainPatchData* sphericalTerrainData,\n                                 f64 width) {\n    m_gridPos = gridPosition;\n    m_cubeFace = cubeFace;\n    m_lod = lod;\n    m_terrainPatchData = sphericalTerrainData;\n    m_width = width;\n\n    // Construct an approximate AABB\n    const i32v3& coordMapping = VoxelSpaceConversions::VOXEL_TO_WORLD[(int)m_cubeFace];\n    const i32v2& coordMults = VoxelSpaceConversions::FACE_TO_WORLD_MULTS[(int)m_cubeFace];\n    f64v3 corners[4];\n    corners[0][coordMapping.x] = gridPosition.x * coordMults.x;\n    corners[0][coordMapping.y] = m_terrainPatchData->radius * VoxelSpaceConversions::FACE_Y_MULTS[(int)m_cubeFace];\n    corners[0][coordMapping.z] = gridPosition.y * coordMults.y;\n    corners[0] = glm::normalize(corners[0]) * m_terrainPatchData->radius;\n    corners[1][coordMapping.x] = gridPosition.x * coordMults.x;\n    corners[1][coordMapping.y] = m_terrainPatchData->radius * VoxelSpaceConversions::FACE_Y_MULTS[(int)m_cubeFace];\n    corners[1][coordMapping.z] = (gridPosition.y + m_width) * coordMults.y;\n    corners[1] = glm::normalize(corners[1]) * m_terrainPatchData->radius;\n    corners[2][coordMapping.x] = (gridPosition.x + m_width) * coordMults.x;\n    corners[2][coordMapping.y] = m_terrainPatchData->radius * VoxelSpaceConversions::FACE_Y_MULTS[(int)m_cubeFace];\n    corners[2][coordMapping.z] = (gridPosition.y + m_width) * coordMults.y;\n    corners[2] = glm::normalize(corners[2]) * m_terrainPatchData->radius;\n    corners[3][coordMapping.x] = (gridPosition.x + m_width) * coordMults.x;\n    corners[3][coordMapping.y] = m_terrainPatchData->radius * VoxelSpaceConversions::FACE_Y_MULTS[(int)m_cubeFace];\n    corners[3][coordMapping.z] = gridPosition.y * coordMults.y;\n    corners[3] = glm::normalize(corners[3]) * m_terrainPatchData->radius;\n\n    f64 minX = INT_MAX, maxX = INT_MIN;\n    f64 minY = INT_MAX, maxY = INT_MIN;\n    f64 minZ = INT_MAX, maxZ = INT_MIN;\n    for (int i = 0; i < 4; i++) {\n        auto& c = corners[i];\n        if (c.x < minX) minX = c.x;\n        if (c.x > maxX) maxX = c.x;\n        if (c.y < minY) minY = c.y;\n        if (c.y > maxY) maxY = c.y;\n        if (c.z < minZ) minZ = c.z;\n        if (c.z > maxZ) maxZ = c.z;\n    }\n    // Get world position and bounding box\n    m_aabbPos = f32v3(minX, minY, minZ);\n    m_aabbDims = f32v3(maxX - minX, maxY - minY, maxZ - minZ);\n}\n\nvoid TerrainPatch::update(const f64v3& cameraPos) {\n    // TODO(Matthew): This statement is not used, revisit this function to see if it's going its job correctly.\n    // Calculate distance from camera\n    //f64v3 closestPoint = calculateClosestPointAndDist(cameraPos);\n    \n    if (m_children) {\n        // Check for out of range\n        if (m_distance > m_width * DIST_MAX) {\n            if (!m_mesh) {\n                requestMesh(true);\n            } else if (hasMesh()) {\n                // Out of range, kill children\n                delete[] m_children;\n                m_children = nullptr;\n            }\n        } else if (m_mesh) {\n            // In range, but we need to remove our mesh.\n            // Check to see if all children are renderable\n            bool deleteMesh = true;\n            for (int i = 0; i < 4; i++) {\n                if (!m_children[i].isRenderable()) {\n                    deleteMesh = false;\n                    break;\n                }\n            }\n            \n            if (deleteMesh) {\n                // Children are renderable, free mesh.\n                // Render thread will deallocate.\n                m_mesh->m_shouldDelete = true;\n                m_mesh = nullptr;\n            }\n        }\n    } else if (canSubdivide()) {\n        m_children = new TerrainPatch[4];\n        // Segment into 4 children\n        for (int z = 0; z < 2; z++) {\n            for (int x = 0; x < 2; x++) {\n                m_children[(z << 1) + x].init(m_gridPos + f64v2((m_width / 2.0) * x, (m_width / 2.0) * z),\n                                                m_cubeFace, m_lod + 1, m_terrainPatchData, m_width / 2.0);\n            }\n        }\n    } else if (!m_mesh) {\n        requestMesh(true);\n    }\n    \n    // Recursively update children if they exist\n    if (m_children) {\n        for (int i = 0; i < 4; i++) {\n            m_children[i].update(cameraPos);\n        }\n    }\n}\n\nvoid TerrainPatch::destroy() {\n    if (m_mesh) {\n        m_mesh->m_shouldDelete = true;\n        m_mesh = nullptr;\n    }\n    delete[] m_children;\n    m_children = nullptr;\n}\n\nbool TerrainPatch::hasMesh() const {\n    return (m_mesh && m_mesh->m_isRenderable);\n}\n\nbool TerrainPatch::isRenderable() const {\n    if (hasMesh()) return true;\n    if (m_children) {\n        for (int i = 0; i < 4; i++) {\n            if (!m_children[i].isRenderable()) return false;\n        }\n        return true;\n    }\n    return false;\n}\n\nbool TerrainPatch::isOverHorizon(const f64v3 &relCamPos, const f64v3 &point, f64 planetRadius) {\n    const f64 DELTA = 0.1;\n    f64 camHeight = glm::length(relCamPos);\n    f64v3 normalizedCamPos = relCamPos / camHeight;\n\n    // Limit the camera depth\n    if (camHeight < planetRadius + 1.0) camHeight = planetRadius + 1.0;\n\n    f64 horizonAngle = acos(planetRadius / camHeight);\n    f64 lodAngle = acos(glm::dot(normalizedCamPos, glm::normalize(point)));\n    if (lodAngle >= horizonAngle + DELTA) {\n        return true;\n    }\n    return false;\n}\n\nvoid TerrainPatch::setQuality(int quality) {\n    // Prevent infinite loop memory allocation due to bad input\n    if (quality < 0 || quality > 6) {\n        fprintf(stderr, \"ERROR: Bad terrain quality: %d\", quality);\n        return;\n    }\n    DIST_MIN = (f32)quality;\n    DIST_MAX = DIST_MIN + 0.1f;\n    PATCH_MAX_LOD = 22 + quality * 2;\n}\n\nbool TerrainPatch::canSubdivide() const {\n    return (m_lod < PATCH_MAX_LOD && m_distance < m_width * DIST_MIN && m_width > MIN_SIZE);\n}\n\nvoid TerrainPatch::requestMesh(bool isSpherical) {\n   \n    f32v3 startPos(m_gridPos.x,\n                   m_terrainPatchData->radius,\n                   m_gridPos.y);\n    m_mesh = new TerrainPatchMesh(m_cubeFace, isSpherical);\n    TerrainPatchMeshTask* meshTask = new TerrainPatchMeshTask();\n    meshTask->init(m_terrainPatchData,\n                   m_mesh,\n                   startPos,\n                   (f32)m_width,\n                   m_cubeFace);\n    m_terrainPatchData->threadPool->addTask(meshTask);\n}\n\nf64v3 TerrainPatch::calculateClosestPointAndDist(const f64v3& cameraPos) {\n    f64v3 closestPoint;\n    // TODO(Ben): The 0 is a temporary oscillation fix\n    if (0 && hasMesh()) {\n        // If we have a mesh, we can use it's accurate bounding box    \n        closestPoint = m_mesh->getClosestPoint(cameraPos);\n    } else {\n        closestPoint = getClosestPointOnAABB(cameraPos, m_aabbPos, m_aabbDims);\n    }\n    m_distance = glm::length(closestPoint - cameraPos);\n    return closestPoint;\n}\n"
  },
  {
    "path": "SoA/TerrainPatch.h",
    "content": "///\n/// TerrainPatch.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 15 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// A terrain patch for use with a SphericalTerrainComponent\n///\n\n#pragma once\n\n#ifndef TerrainPatch_h__\n#define TerrainPatch_h__\n\n#include \"VoxelCoordinateSpaces.h\"\n#include \"TerrainPatchConstants.h\"\n#include \"VoxPool.h\"\n\n#include <Vorb/graphics/gtypes.h>\n\nclass TerrainPatchMesh;\nclass TerrainPatchMesher;\nclass SphericalHeightmapGenerator;\nclass TerrainPatchMeshManager;\n\n// Shared data for terrain patches\nstruct TerrainPatchData { // TODO(Ben): probably dont need this\n    friend struct SphericalTerrainComponent;\n\n    TerrainPatchData(f64 radius, f64 patchWidth,\n                     SphericalHeightmapGenerator* generator,\n                     TerrainPatchMeshManager* meshManager,\n                     vcore::ThreadPool<WorkerData>* threadPool) :\n        radius(radius),\n        patchWidth(patchWidth),\n        generator(generator),\n        meshManager(meshManager),\n        threadPool(threadPool) {\n        // Empty\n    }\n\n    f64 radius; ///< Radius of the planet in KM\n    f64 patchWidth; ///< Width of a patch in KM\n    SphericalHeightmapGenerator* generator;\n    TerrainPatchMeshManager* meshManager;\n    vcore::ThreadPool<WorkerData>* threadPool;\n};\n\n// TODO(Ben): Sorting\n// fix redundant quality changes\nclass TerrainPatch {\npublic:\n    TerrainPatch() { };\n    virtual ~TerrainPatch();\n    \n    /// Initializes the patch\n    /// @param gridPosition: Position on the 2d face grid\n    /// @param sphericalTerrainData: Shared data\n    /// @param width: Width of the patch in KM\n    virtual void init(const f64v2& gridPosition,\n              WorldCubeFace cubeFace,\n              int lod,\n              const TerrainPatchData* sphericalTerrainData,\n              f64 width);\n\n    /// Updates the patch\n    /// @param cameraPos: Position of the camera\n    virtual void update(const f64v3& cameraPos);\n\n    /// Frees resources\n    void destroy();\n\n    /// @return true if it has a generated mesh\n    bool hasMesh() const;\n\n    /// @return true if it has a mesh, or all of its children are\n    /// renderable.\n    bool isRenderable() const;\n\n                            \n    static bool isOverHorizon(const f64v3 &relCamPos, const f64v3 &point, f64 planetRadius);\n\n    static void setQuality(int quality);\n\n    /// Returns true if the patch can subdivide\n    bool canSubdivide() const;\nprotected:\n    /// Requests a mesh via RPC\n    void requestMesh(bool isSpherical);\n    /// Calculates the closest point to the camera, as well as distance\n    /// @param cameraPos: position of the observer\n    /// @return closest point on the AABB\n    f64v3 calculateClosestPointAndDist(const f64v3& cameraPos);\n\n    static f32 DIST_MIN;\n    static f32 DIST_MAX;\n    static f32 MIN_SIZE;\n    static int PATCH_MAX_LOD;\n\n    f64v2 m_gridPos = f64v2(0.0); ///< Position on 2D grid\n    f64v3 m_aabbPos = f64v3(0.0); ///< Position relative to world\n    f64v3 m_aabbDims = f64v3(0.0);\n    f64 m_distance = 1000000000.0; ///< Distance from camera\n    int m_lod = 0; ///< Level of detail\n    WorldCubeFace m_cubeFace; ///< Which cube face grid it is on\n\n    f64 m_width = 0.0; ///< Width of the patch in KM\n\n    TerrainPatchMesh* m_mesh = nullptr;\n\n    const TerrainPatchData* m_terrainPatchData = nullptr; ///< Shared data pointer\n    TerrainPatch* m_children = nullptr; ///< Pointer to array of 4 children\n};\n\n#endif // TerrainPatch_h__"
  },
  {
    "path": "SoA/TerrainPatchConstants.h",
    "content": "///\n/// TerrainPatchConstants.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 17 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Constants for terrain patch stuff\n///\n\n#pragma once\n\n#ifndef TerrainPatchConstants_h__\n#define TerrainPatchConstants_h__\n\nconst int PATCH_NORMALMAP_PIXELS_PER_QUAD = 4; ///< Pixels of normalMap per quad\nconst int PATCH_WIDTH = 33; ///< Width of patches in vertices\nconst int PADDED_PATCH_WIDTH = PATCH_WIDTH + 2; ///< Width of patches in vertices\nconst int PATCH_SIZE = PATCH_WIDTH * PATCH_WIDTH; ///< Size of patches in vertices\nconst int PATCH_NORMALMAP_WIDTH = (PATCH_WIDTH - 1) * PATCH_NORMALMAP_PIXELS_PER_QUAD + 2; ///< Width of normalmap in pixels, + 2 for padding\nconst int PATCH_HEIGHTMAP_WIDTH = PATCH_NORMALMAP_WIDTH + 2; ///< Width of heightmap in pixels, + 2 for padding\nconst int TEXELS_PER_PATCH = PATCH_NORMALMAP_WIDTH - 2; ///< The number of texels contained in a patch.\n\nconst int NUM_SKIRTS = 4;\nconst int INDICES_PER_QUAD = 6; ///< Indices used to render a quad with glDrawElements\nconst int PATCH_INDICES = (PATCH_WIDTH - 1) * (PATCH_WIDTH - 1 + NUM_SKIRTS) * INDICES_PER_QUAD; ///< Total indices in a patch\nconst int PATCH_INDICES_NO_SKIRTS = (PATCH_WIDTH - 1) * (PATCH_WIDTH - 1) * INDICES_PER_QUAD; ///< Total indices in a patch with no skirts\n\n#endif // TerrainPatchConstants_h__\n"
  },
  {
    "path": "SoA/TerrainPatchMesh.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TerrainPatchMesh.h\"\n\n#include <Vorb/TextureRecycler.hpp>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GpuMemory.h>\n\n#include \"Camera.h\"\n#include \"RenderUtils.h\"\n#include \"soaUtils.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include \"VoxelSpaceConversions.h\"\n\nTerrainPatchMesh::~TerrainPatchMesh() {\n    if (m_vbo) {\n        vg::GpuMemory::freeBuffer(m_vbo);\n    }\n    if (m_wvbo) {\n        vg::GpuMemory::freeBuffer(m_wvbo);\n    }\n    if (m_wibo) {\n        vg::GpuMemory::freeBuffer(m_wibo);\n    }\n    if (m_vao) {\n        glDeleteVertexArrays(1, &m_vao);\n    }\n    if (m_wvao) {\n        glDeleteVertexArrays(1, &m_wvao);\n    }\n}\n\nvoid TerrainPatchMesh::draw(const f32m4& WVP, const vg::GLProgram& program,\n                            bool drawSkirts) const {\n    glUniformMatrix4fv(program.getUniform(\"unWVP\"), 1, GL_FALSE, &WVP[0][0]);\n\n    glBindVertexArray(m_vao);\n\n    if (drawSkirts) {\n        glDrawElements(GL_TRIANGLES, PATCH_INDICES, GL_UNSIGNED_SHORT, 0);\n    } else {\n        glDrawElements(GL_TRIANGLES, PATCH_INDICES_NO_SKIRTS, GL_UNSIGNED_SHORT, 0);\n    }\n    glBindVertexArray(0);\n}\n\nvoid TerrainPatchMesh::drawWater(const f32m4& WVP, const vg::GLProgram& program) const {\n    glUniformMatrix4fv(program.getUniform(\"unWVP\"), 1, GL_FALSE, &WVP[0][0]);\n\n    glBindVertexArray(m_wvao);\n\n    glDrawElements(GL_TRIANGLES, m_waterIndexCount, GL_UNSIGNED_SHORT, 0);\n\n    glBindVertexArray(0);\n}\n\nvoid TerrainPatchMesh::drawAsFarTerrain(const f64v3& relativePos, const f32m4& VP,\n                                        const vg::GLProgram& program,\n                                        bool drawSkirts) const {\n    // No need for matrix with simple translation\n    f32v3 translation = f32v3(f64v3(m_aabbPos) - relativePos);\n\n    glUniformMatrix4fv(program.getUniform(\"unVP\"), 1, GL_FALSE, &VP[0][0]);\n    glUniform3fv(program.getUniform(\"unTranslation\"), 1, &translation[0]);\n    glUniform3fv(program.getUniform(\"unPosition\"), 1, &m_aabbPos[0]);\n\n    glBindVertexArray(m_vao);\n\n    if (drawSkirts) {\n        glDrawElements(GL_TRIANGLES, PATCH_INDICES, GL_UNSIGNED_SHORT, 0);\n    } else {\n        glDrawElements(GL_TRIANGLES, PATCH_INDICES_NO_SKIRTS, GL_UNSIGNED_SHORT, 0);\n    }\n\n    glBindVertexArray(0);\n}\n\n/// Draws the water mesh as a far terrain mesh\nvoid TerrainPatchMesh::drawWaterAsFarTerrain(const f64v3& relativePos, const f32m4& VP,\n                                             const vg::GLProgram& program) const {\n    // No need for matrix with simple translation\n    f32v3 translation = f32v3(f64v3(m_aabbPos) - relativePos);\n\n    glUniformMatrix4fv(program.getUniform(\"unVP\"), 1, GL_FALSE, &VP[0][0]);\n    glUniform3fv(program.getUniform(\"unTranslation\"), 1, &translation[0]);\n    glUniform3fv(program.getUniform(\"unPosition\"), 1, &m_aabbPos[0]);\n\n    glBindVertexArray(m_wvao);\n\n    glDrawElements(GL_TRIANGLES, m_waterIndexCount, GL_UNSIGNED_SHORT, 0);\n\n    glBindVertexArray(0);\n}\n\nf32v3 TerrainPatchMesh::getClosestPoint(const f32v3& camPos) const {\n    return getClosestPointOnAABB(camPos, m_aabbPos, m_aabbDims);\n}\nf64v3 TerrainPatchMesh::getClosestPoint(const f64v3& camPos) const {\n    return getClosestPointOnAABB(camPos, f64v3(m_aabbPos), f64v3(m_aabbDims));\n}\n"
  },
  {
    "path": "SoA/TerrainPatchMesh.h",
    "content": "///\n/// TerrainPatchMesh.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 17 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Defines mesh for TerrainPatches\n///\n\n#pragma once\n\n#ifndef TerrainPatchMesh_h__\n#define TerrainPatchMesh_h__\n\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/VorbPreDecl.inl>\n\n#include \"VoxelCoordinateSpaces.h\"\n#include \"TerrainPatchConstants.h\"\n\nclass Camera;\nDECL_VG(class TextureRecycler);\nDECL_VG(class GLProgram);\n\n/// Vertex for terrain patch\nclass TerrainVertex {\npublic:\n    f32v3 position; //12\n    f32v3 normal; //24\n    ColorRGB8 color; //27\n    ui8 padding; //28\n    ui8 temperature; //29\n    ui8 humidity; //30\n    ui8 padding2[2]; //32\n};\n/// Water vertex for terrain patch\nclass WaterVertex {\npublic:\n    f32v3 position; //12\n    f32v3 tangent; //24\n    ColorRGB8 color; //27\n    ui8 temperature; //28\n    float depth; //32\n};\n\nclass TerrainPatchMesh {\npublic:\n    friend class FarTerrainPatch;\n    friend class TerrainPatch;\n    friend class TerrainPatchMeshManager;\n    friend class TerrainPatchMeshTask;\n    friend class TerrainPatchMesher;\n    TerrainPatchMesh(WorldCubeFace cubeFace, bool isSpherical) :\n        m_cubeFace(cubeFace), m_isSpherical(isSpherical) {}\n    ~TerrainPatchMesh();\n\n    /// Recycles the normal map\n    /// @param recycler: Recycles the texture\n    void recycleNormalMap(vg::TextureRecycler* recycler);\n\n    /// Draws the terrain mesh\n    void draw(const f32m4& WVP, const vg::GLProgram& program,\n              bool drawSkirts) const;\n\n    /// Draws the water mesh\n    void drawWater(const f32m4& WVP, const vg::GLProgram& program) const;\n\n    /// Draws the terrain mesh as a far terrain mesh\n    void drawAsFarTerrain(const f64v3& relativePos, const f32m4& VP,\n                          const vg::GLProgram& program,\n                          bool drawSkirts) const;\n\n    /// Draws the water mesh as a far terrain mesh\n    void drawWaterAsFarTerrain(const f64v3& relativePos, const f32m4& VP,\n                               const vg::GLProgram& program) const;\n\n\n    /// Gets the point closest to the observer\n    /// @param camPos: Position of observer\n    /// @return the closest point on the aabb\n    f32v3 getClosestPoint(const f32v3& camPos) const;\n    f64v3 getClosestPoint(const f64v3& camPos) const;\n    const bool& getIsSpherical() const { return m_isSpherical; }\n\n    f64 distance2 = 100000000000.0;\nprivate:\n    VGVertexArray m_vao = 0; ///< Vertex array object\n    VGVertexBuffer m_vbo = 0; ///< Vertex buffer object\n  \n    VGVertexArray m_wvao = 0; ///< Water vertex array object\n    VGVertexBuffer m_wvbo = 0; ///< Water Vertex buffer object\n    VGIndexBuffer m_wibo = 0; ///< Water Index Buffer Object\n\n    f32v3 m_aabbPos = f32v3(0.0f); ///< Bounding box origin\n    f32v3 m_aabbDims = f32v3(0.0f); ///< Bounding box dims\n    f32v3 m_aabbCenter = f32v3(0.0f); ///< Center of the bounding box\n    f32 m_boundingSphereRadius = 0.0f; ///< Radius of sphere for frustum checks\n    WorldCubeFace m_cubeFace;\n\n    std::vector<ui8> m_meshDataBuffer; ///< Stores mesh data for terrain and water in bytes\n\n    int m_waterIndexCount = 0;\n    int m_waterVertexCount = 0;\n\n    volatile bool m_shouldDelete = false; ///< True when the mesh should be deleted\n    bool m_isRenderable = false; ///< True when there is a complete mesh\n    bool m_isSpherical = false;\n};\n\n#endif // TerrainPatchMesh_h__\n"
  },
  {
    "path": "SoA/TerrainPatchMeshManager.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TerrainPatchMeshManager.h\"\n\n#include \"Errors.h\"\n#include \"PlanetGenLoader.h\"\n#include \"Camera.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/TextureRecycler.hpp>\n\n#include \"FarTerrainPatch.h\"\n#include \"PlanetGenData.h\"\n#include \"RenderUtils.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"TerrainPatch.h\"\n#include \"TerrainPatchMesh.h\"\n#include \"soaUtils.h\"\n\n#define MAX_UPDATES_PER_FRAME 100\n\nvoid TerrainPatchMeshManager::update() {\n    TerrainPatchMesh* meshes[MAX_UPDATES_PER_FRAME];\n    if (size_t numUpdates = m_meshesToAdd.try_dequeue_bulk(meshes, MAX_UPDATES_PER_FRAME)) {\n        for (size_t i = 0; i < numUpdates; i++) {\n            addMesh(meshes[i]);\n        }\n    }\n}\n\nvoid TerrainPatchMeshManager::drawSphericalMeshes(const f64v3& relativePos,\n                                                  const Camera* camera,\n                                                  const f64q& orientation,\n                                                  vg::GLProgram& program,\n                                                  vg::GLProgram& waterProgram,\n                                                  const f32v3& lightDir,\n                                                  f32 alpha,\n                                                  const f32 zCoef,\n                                                  const AtmosphereComponent* aCmp,\n                                                  bool drawSkirts) {\n    \n    static f32 dt = 0.0f;\n    dt += 0.00003f;\n\n    f64q invOrientation = glm::inverse(orientation);\n    const f64v3 rotpos = invOrientation * relativePos;\n    const f32v3 rotLightDir = f32v3(invOrientation * f64v3(lightDir));\n    // Convert f64q to f32q\n    f32q orientationF32;\n    orientationF32.x = (f32)orientation.x;\n    orientationF32.y = (f32)orientation.y;\n    orientationF32.z = (f32)orientation.z;\n    orientationF32.w = (f32)orientation.w;\n    // Convert to matrix\n    f32m4 rotationMatrix = glm::toMat4(orientationF32);\n    f32m4 W(1.0);\n    setMatrixTranslation(W, -relativePos);\n    f32m4 WVP = camera->getViewProjectionMatrix() * W * rotationMatrix;\n\n    if (m_waterMeshes.size()) {\n        // Bind textures\n        glActiveTexture(GL_TEXTURE1);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->liquidColorMap.id);\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->liquidTexture.id);\n        waterProgram.use();\n        waterProgram.enableVertexAttribArrays();\n        // Set uniforms\n        glUniform1f(waterProgram.getUniform(\"unDt\"), dt);\n        glUniform1f(waterProgram.getUniform(\"unDepthScale\"), m_planetGenData->liquidDepthScale);\n        glUniform1f(waterProgram.getUniform(\"unFreezeTemp\"), m_planetGenData->liquidFreezeTemp / 255.0f);\n        glUniform3fv(waterProgram.getUniform(\"unLightDirWorld\"), 1, &rotLightDir[0]);\n        glUniform1f(waterProgram.getUniform(\"unAlpha\"), alpha);\n        // For logarithmic Z buffer\n        glUniform1f(waterProgram.getUniform(\"unZCoef\"), zCoef);\n        // Set up scattering uniforms\n        setScatterUniforms(waterProgram, rotpos, aCmp);\n\n        for (size_t i = 0; i < m_waterMeshes.size();) {\n            auto& m = m_waterMeshes[i];\n            if (m->m_shouldDelete) {\n                // Only delete here if m_wvbo is 0. See comment [15] in below block\n                if (m->m_wvbo) {\n                    vg::GpuMemory::freeBuffer(m->m_wvbo);\n                } else {\n                    delete m;\n                }\n\n                m = m_waterMeshes.back();\n                m_waterMeshes.pop_back();\n              \n            } else {\n                // TODO(Ben): Horizon and frustum culling for water too\n                m->drawWater(WVP, waterProgram);\n                i++;\n            }\n        }\n        waterProgram.disableVertexAttribArrays();\n        waterProgram.unuse();\n    }\n\n    if (m_meshes.size()) {\n        // Bind textures\n        glActiveTexture(GL_TEXTURE1);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->terrainColorMap.id);\n        glActiveTexture(GL_TEXTURE2);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->grassTexture.id);\n        glActiveTexture(GL_TEXTURE3);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->rockTexture.id);\n        glActiveTexture(GL_TEXTURE0);\n        program.use();\n        program.enableVertexAttribArrays();\n        // For logarithmic Z buffer\n        glUniform1f(program.getUniform(\"unZCoef\"), zCoef);\n        glUniform3fv(program.getUniform(\"unLightDirWorld\"), 1, &rotLightDir[0]);\n        glUniform1f(program.getUniform(\"unAlpha\"), alpha);\n        // Set up scattering uniforms\n        setScatterUniforms(program, rotpos, aCmp);\n\n        for (size_t i = 0; i < m_meshes.size();) {\n            auto& m = m_meshes[i];\n\n            if (m->m_shouldDelete) {\n                // [15] If m_wvbo is 1, then chunk was marked for delete between\n                // Drawing water and terrain. So we free m_wvbo to mark it\n                // for delete on the next pass through m_waterMeshes\n                if (m->m_wvbo) {\n                    vg::GpuMemory::freeBuffer(m->m_wvbo);\n                } else {\n                    delete m;\n                }\n\n                m = m_meshes.back();\n                m_meshes.pop_back();\n            } else {\n                /// Use bounding box to find closest point\n                f64v3 closestPoint = m->getClosestPoint(rotpos);\n                \n                // Check horizon culling first, it's more likely to cull spherical patches\n                if (!TerrainPatch::isOverHorizon(rotpos, closestPoint,\n                    m_planetGenData->radius)) {\n                    // Check frustum culling\n                    // TODO(Ben): There could be a way to reduce the number of frustum checks\n                    // via caching or checking a parent\n                    f32v3 relSpherePos = orientationF32 * m->m_aabbCenter - f32v3(relativePos);\n                    if (camera->sphereInFrustum(relSpherePos,\n                        m->m_boundingSphereRadius)) {\n                        m->draw(WVP, program, drawSkirts);\n                    }\n                }\n                i++;\n            }\n        }\n        program.disableVertexAttribArrays();\n        program.unuse();\n    }\n}\n\nTerrainPatchMeshManager::~TerrainPatchMeshManager() {\n    for (auto& i : m_meshes) {\n        delete i;\n    }\n    for (auto& i : m_farMeshes) {\n        delete i;\n    }\n}\n\nvoid TerrainPatchMeshManager::addMesh(TerrainPatchMesh* mesh) {\n    // Upload data\n    if (mesh->m_meshDataBuffer.size()) {\n        TerrainPatchMesher::uploadMeshData(mesh);\n    }\n    // Add to mesh list\n    if (mesh->getIsSpherical()) {\n        m_meshes.push_back(mesh);\n        if (mesh->m_wvbo) {\n            m_waterMeshes.push_back(mesh);\n        }\n    } else {\n        m_farMeshes.push_back(mesh);\n        if (mesh->m_wvbo) {\n            m_farWaterMeshes.push_back(mesh);\n        }\n    }\n    mesh->m_isRenderable = true;\n}\n\nvoid TerrainPatchMeshManager::addMeshAsync(TerrainPatchMesh* mesh) {\n    m_meshesToAdd.enqueue(mesh);\n}\n\nbool meshComparator(TerrainPatchMesh* m1, TerrainPatchMesh* m2) {\n    return (m1->distance2 < m2->distance2);\n}\n\nvoid TerrainPatchMeshManager::sortSpericalMeshes(const f64v3& relPos) {\n    // Calculate squared distances\n    for (auto& mesh : m_meshes) {\n        f64v3 distVec = mesh->getClosestPoint(relPos) - relPos;\n        mesh->distance2 = selfDot(distVec);\n    }\n\n    // Not sorting water since it would be of minimal benifit\n    std::sort(m_meshes.begin(), m_meshes.end(), [](TerrainPatchMesh* m1, TerrainPatchMesh* m2) -> bool {\n        return (m1->distance2 < m2->distance2);\n    });\n}\n\nvoid TerrainPatchMeshManager::sortFarMeshes(const f64v3& relPos) {\n    // Calculate squared distances\n    for (auto& mesh : m_farMeshes) {\n        f64v3 distVec = mesh->getClosestPoint(relPos) - relPos;\n        mesh->distance2 = selfDot(distVec);\n    }\n\n    // Not sorting water since it would be of minimal benifit\n    std::sort(m_farMeshes.begin(), m_farMeshes.end(), [](TerrainPatchMesh* m1, TerrainPatchMesh* m2) -> bool {\n        return (m1->distance2 < m2->distance2);\n    });\n}\n\nvoid TerrainPatchMeshManager::drawFarMeshes(const f64v3& relativePos,\n                                            const Camera* camera,\n                                            vg::GLProgram& program,\n                                            vg::GLProgram& waterProgram,\n                                            const f32v3& lightDir,\n                                            f32 alpha, f32 radius,\n                                            const f32 zCoef,\n                                            const AtmosphereComponent* aCmp,\n                                            bool drawSkirts) {\n    // TODO(Ben): This will lose precision over time\n    static f32 dt = 0.0f;\n    dt += 0.0001f;\n\n    if (m_farWaterMeshes.size()) {\n        // Bind textures\n        glActiveTexture(GL_TEXTURE1);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->liquidColorMap.id);\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->liquidTexture.id);\n        waterProgram.use();\n        waterProgram.enableVertexAttribArrays();\n        // Set uniforms\n        glUniform1f(waterProgram.getUniform(\"unDt\"), dt);\n        glUniform1f(waterProgram.getUniform(\"unDepthScale\"), m_planetGenData->liquidDepthScale);\n        glUniform1f(waterProgram.getUniform(\"unFreezeTemp\"), m_planetGenData->liquidFreezeTemp / 255.0f);\n        glUniform1f(waterProgram.getUniform(\"unRadius\"), radius);\n        glUniform3fv(waterProgram.getUniform(\"unLightDirWorld\"), 1, &lightDir[0]);\n        glUniform1f(waterProgram.getUniform(\"unAlpha\"), alpha);\n        // For logarithmic Z buffer\n        glUniform1f(waterProgram.getUniform(\"unZCoef\"), zCoef);\n        // Set up scattering uniforms\n        setScatterUniforms(waterProgram, f64v3(0, relativePos.y + radius, 0), aCmp);\n\n        for (size_t i = 0; i < m_farWaterMeshes.size();) {\n            auto& m = m_farWaterMeshes[i];\n            if (m->m_shouldDelete) {\n                // Only delete here if m_wvbo is 0. See comment [15] in below block\n                if (m->m_wvbo) {\n                    vg::GpuMemory::freeBuffer(m->m_wvbo);\n                } else {\n                    delete m;\n                }\n\n                m = m_farWaterMeshes.back();\n                m_farWaterMeshes.pop_back();\n\n            } else {\n                m->drawWaterAsFarTerrain(relativePos, camera->getViewProjectionMatrix(), waterProgram);\n                i++;\n            }\n        }\n        waterProgram.disableVertexAttribArrays();\n        waterProgram.unuse();\n    }\n\n    if (m_farMeshes.size()) {\n        // Bind textures\n        glActiveTexture(GL_TEXTURE1);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->terrainColorMap.id);\n        glActiveTexture(GL_TEXTURE2);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->grassTexture.id);\n        glActiveTexture(GL_TEXTURE3);\n        glBindTexture(GL_TEXTURE_2D, m_planetGenData->rockTexture.id);\n        glActiveTexture(GL_TEXTURE0);\n        program.use();\n        program.enableVertexAttribArrays();\n        glUniform1f(program.getUniform(\"unRadius\"), radius); // TODO(Ben): Use real radius\n        glUniform3fv(program.getUniform(\"unLightDirWorld\"), 1, &lightDir[0]);\n        glUniform1f(program.getUniform(\"unAlpha\"), alpha);\n        // For logarithmic Z buffer\n        glUniform1f(program.getUniform(\"unZCoef\"), zCoef);\n        // Set up scattering uniforms\n        setScatterUniforms(program, f64v3(0, relativePos.y + radius, 0), aCmp);\n\n        for (size_t i = 0; i < m_farMeshes.size();) {\n            auto& m = m_farMeshes[i];\n            if (m->m_shouldDelete) {\n                // [15] If m_wvbo is 1, then chunk was marked for delete between\n                // Drawing water and terrain. So we free m_wvbo to mark it\n                // for delete on the next pass through m_farWaterMeshes\n                if (m->m_wvbo) {\n                    vg::GpuMemory::freeBuffer(m->m_wvbo);\n                } else {\n                    delete m;\n                }\n\n                m = m_farMeshes.back();\n                m_farMeshes.pop_back();\n            } else {\n                // Check frustum culling\n                // TODO(Ben): There could be a way to reduce the number of frustum checks\n                // via caching or checking a parent\n                // Check frustum culling first, it's more likely to cull far patches\n                f32v3 relSpherePos = m->m_aabbCenter - f32v3(relativePos);\n                if (camera->sphereInFrustum(relSpherePos, m->m_boundingSphereRadius)) {\n                    /// Use bounding box to find closest point\n                    f64v3 closestPoint = m->getClosestPoint(relativePos);\n                    if (!FarTerrainPatch::isOverHorizon(relativePos, closestPoint,\n                        m_planetGenData->radius)) {\n                        m->drawAsFarTerrain(relativePos, camera->getViewProjectionMatrix(), program, drawSkirts);\n                    }\n                }\n                i++;\n            }\n        }\n        program.disableVertexAttribArrays();\n        program.unuse();\n    }\n}\n\nvoid TerrainPatchMeshManager::setScatterUniforms(vg::GLProgram& program, const f64v3& relPos, const AtmosphereComponent* aCmp) {\n    // Set up scattering uniforms\n    if (aCmp) {\n        f32v3 relPosF(relPos);\n        f32 camHeight = glm::length(relPosF);\n        glUniform3fv(program.getUniform(\"unCameraPos\"), 1, &relPosF[0]);\n        glUniform3fv(program.getUniform(\"unInvWavelength\"), 1, &aCmp->invWavelength4[0]);\n        glUniform1f(program.getUniform(\"unCameraHeight2\"), camHeight * camHeight);\n        glUniform1f(program.getUniform(\"unInnerRadius\"), aCmp->planetRadius);\n        glUniform1f(program.getUniform(\"unOuterRadius\"), aCmp->radius);\n        glUniform1f(program.getUniform(\"unOuterRadius2\"), aCmp->radius * aCmp->radius);\n        glUniform1f(program.getUniform(\"unKrESun\"), aCmp->kr * aCmp->esun);\n        glUniform1f(program.getUniform(\"unKmESun\"), aCmp->km * aCmp->esun);\n        glUniform1f(program.getUniform(\"unKr4PI\"), (f32)(aCmp->kr * M_4_PI));\n        glUniform1f(program.getUniform(\"unKm4PI\"), (f32)(aCmp->km * M_4_PI));\n        f32 scale = 1.0f / (aCmp->radius - aCmp->planetRadius);\n        glUniform1f(program.getUniform(\"unScale\"), scale);\n        glUniform1f(program.getUniform(\"unScaleDepth\"), aCmp->scaleDepth);\n        glUniform1f(program.getUniform(\"unScaleOverScaleDepth\"), scale / aCmp->scaleDepth);\n        glUniform1i(program.getUniform(\"unNumSamples\"), 3);\n        glUniform1f(program.getUniform(\"unNumSamplesF\"), 3.0f);\n        glUniform1f(program.getUniform(\"unG\"), aCmp->g);\n        glUniform1f(program.getUniform(\"unG2\"), aCmp->g * aCmp->g);\n    }\n}\n"
  },
  {
    "path": "SoA/TerrainPatchMeshManager.h",
    "content": "///\n/// TerrainPatchMeshManager.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 17 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Simple container for terrain meshes. Each planet gets one\n///\n#include \"TerrainPatch.h\"\n\n#pragma once\n\n#ifndef TerrainPatchMeshManager_h__\n#define TerrainPatchMeshManager_h__\n\n#include <Vorb/vorb_rpc.h>\n#include <Vorb/VorbPreDecl.inl>\n\nclass Camera;\nclass TerrainPatchMesh;\nstruct AtmosphereComponent;\nstruct PlanetGenData;\nstruct TerrainPatchData;\n\nDECL_VG(class TextureRecycler;\n        class GLProgram)\n\nclass TerrainPatchMeshManager {\npublic:\n    TerrainPatchMeshManager(const PlanetGenData* planetGenData) :\n        m_planetGenData(planetGenData){\n        // Empty\n    }\n    ~TerrainPatchMeshManager();\n\n    void update();\n\n    /// Draws the spherical meshes\n    /// @param relativePos: Relative position of the camera\n    /// @param Camera: The camera\n    /// @param orientation: Orientation quaternion\n    /// @param program: Shader program for rendering terrain\n    /// @param waterProgram: Shader program for rendering water\n    /// @param lightDir: Normalized direction to light source\n    /// @param aCmp: Atmosphere component for rendering\n    /// @param drawSkirts: True when you want to also draw skirts\n    void drawSphericalMeshes(const f64v3& relativePos,\n                             const Camera* camera,\n                             const f64q& orientation,\n                             vg::GLProgram& program, vg::GLProgram& waterProgram,\n                             const f32v3& lightDir,\n                             f32 alpha,\n                             const f32 zCoef,\n                             const AtmosphereComponent* aCmp,\n                             bool drawSkirts);\n    /// Draws the far meshes\n    /// @param relativePos: Relative position of the camera\n    /// @param Camera: The camera state\n    /// @param orientation: Orientation quaternion\n    /// @param program: Shader program for rendering terrain\n    /// @param waterProgram: Shader program for rendering water\n    /// @param lightDir: Normalized direction to light source\n    /// @param radius: Radius of the planet in KM\n    /// @param aCmp: Atmosphere component for rendering\n    /// @param drawSkirts: True when you want to also draw skirts\n    void drawFarMeshes(const f64v3& relativePos,\n                       const Camera* camera,\n                       vg::GLProgram& program, vg::GLProgram& waterProgram,\n                       const f32v3& lightDir,\n                       f32 alpha, f32 radius,\n                       const f32 zCoef,\n                       const AtmosphereComponent* aCmp,\n                       bool drawSkirts);\n\n    /// Adds a mesh \n    void addMesh(TerrainPatchMesh* mesh);\n    /// Adds a mesh from a worker thread\n    void addMeshAsync(TerrainPatchMesh* mesh);\n\n    /// Updates distances and Sorts meshes\n    void sortSpericalMeshes(const f64v3& relPos);\n\n    /// Updates distances and Sorts meshes\n    void sortFarMeshes(const f64v3& relPos);\n\nprivate:\n    void setScatterUniforms(vg::GLProgram& program, const f64v3& relPos, const AtmosphereComponent* aCmp);\n\n    moodycamel::ConcurrentQueue<TerrainPatchMesh*> m_meshesToAdd;\n\n    const PlanetGenData* m_planetGenData = nullptr; ///< Planetary data\n    std::vector<TerrainPatchMesh*> m_meshes; ///< All meshes\n    std::vector<TerrainPatchMesh*> m_waterMeshes; ///< Meshes with water active\n    std::vector<TerrainPatchMesh*> m_farMeshes; ///< All meshes\n    std::vector<TerrainPatchMesh*> m_farWaterMeshes; ///< Meshes with water active\n};\n\n#endif // TerrainPatchMeshManager_h__\n"
  },
  {
    "path": "SoA/TerrainPatchMeshTask.cpp",
    "content": "#include \"stdafx.h\"\n#include \"SphericalHeightmapGenerator.h\"\n#include \"TerrainPatchMesh.h\"\n#include \"TerrainPatchMeshManager.h\"\n#include \"TerrainPatchMeshTask.h\"\n#include \"TerrainPatchMesher.h\"\n#include \"VoxelSpaceConversions.h\"\n\nvoid TerrainPatchMeshTask::init(const TerrainPatchData* patchData,\n                                TerrainPatchMesh* mesh,\n                                const f32v3& startPos,\n                                float width,\n                                WorldCubeFace cubeFace) {\n    m_patchData = patchData;\n    m_mesh = mesh;\n    m_startPos = startPos;\n    m_width = width;\n    m_cubeFace = cubeFace;\n}\n\nvoid TerrainPatchMeshTask::execute(WorkerData* workerData) {\n\n    PlanetHeightData heightData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH];\n    f64v3 positionData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH];\n    f64v3 pos;\n    // f32v3 tmpPos;\n\n    SphericalHeightmapGenerator* generator = m_patchData->generator;\n    if (m_mesh->m_shouldDelete) {\n        delete m_mesh;\n        return;\n    }\n    const float VERT_WIDTH = m_width / (PATCH_WIDTH - 1);\n    bool isSpherical = m_mesh->getIsSpherical();\n\n    if (isSpherical) {\n        const i32v3& coordMapping = VoxelSpaceConversions::VOXEL_TO_WORLD[(int)m_cubeFace];\n        const f32v2& coordMults = f32v2(VoxelSpaceConversions::FACE_TO_WORLD_MULTS[(int)m_cubeFace]);\n      \n        m_startPos.y *= (f32)VoxelSpaceConversions::FACE_Y_MULTS[(int)m_cubeFace];\n        for (int z = 0; z < PADDED_PATCH_WIDTH; z++) {\n            for (int x = 0; x < PADDED_PATCH_WIDTH; x++) {\n                pos[coordMapping.x] = (m_startPos.x + (x - 1) * VERT_WIDTH) * coordMults.x;\n                pos[coordMapping.y] = m_startPos.y;\n                pos[coordMapping.z] = (m_startPos.z + (z - 1) * VERT_WIDTH) * coordMults.y;\n                f64v3 normal(glm::normalize(pos));\n                generator->generateHeightData(heightData[z][x], normal);\n                \n                // offset position by height;\n                positionData[z][x] = normal * (m_patchData->radius + heightData[z][x].height * KM_PER_VOXEL);\n            }\n        }\n    } else { // Far terrain\n        const i32v3& coordMapping = VoxelSpaceConversions::VOXEL_TO_WORLD[(int)m_cubeFace];\n        const f32v2& coordMults = f32v2(VoxelSpaceConversions::FACE_TO_WORLD_MULTS[(int)m_cubeFace]);\n\n        m_startPos.y *= (f32)VoxelSpaceConversions::FACE_Y_MULTS[(int)m_cubeFace];\n        for (int z = 0; z < PADDED_PATCH_WIDTH; z++) {\n            for (int x = 0; x < PADDED_PATCH_WIDTH; x++) {\n                f64v2 spos;\n                spos.x = (m_startPos.x + (x - 1) * VERT_WIDTH);\n                spos.y = (m_startPos.z + (z - 1) * VERT_WIDTH);\n                pos[coordMapping.x] = spos.x * coordMults.x;\n                pos[coordMapping.y] = m_startPos.y;\n                pos[coordMapping.z] = spos.y * coordMults.y;\n                f64v3 normal(glm::normalize(pos));\n                generator->generateHeightData(heightData[z][x], normal);\n\n                // offset position by height;\n                positionData[z][x] = f64v3(spos.x, heightData[z][x].height * KM_PER_VOXEL, spos.y);\n            }\n        }\n    }\n    // Check for early delete\n    if (m_mesh->m_shouldDelete) {\n        delete m_mesh;\n        return;\n    }\n    if (!workerData->terrainMesher) workerData->terrainMesher = new TerrainPatchMesher();\n    workerData->terrainMesher->generateMeshData(m_mesh, generator->getGenData(), m_startPos, m_cubeFace, m_width,\n                                                heightData, positionData);\n\n    // Finally, add to the mesh manager\n    m_patchData->meshManager->addMeshAsync(m_mesh);\n}\n"
  },
  {
    "path": "SoA/TerrainPatchMeshTask.h",
    "content": "///\n/// TerrainPatchMeshTask.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 1 Jul 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Task for terrain patch mesh\n///\n\n#pragma once\n\n#ifndef TerrainPatchMeshTask_h__\n#define TerrainPatchMeshTask_h__\n\n#include <Vorb/IThreadPoolTask.h>\n\n#include \"Constants.h\"\n#include \"VoxPool.h\"\n#include \"VoxelCoordinateSpaces.h\"\n\nstruct TerrainPatchData;\nclass TerrainPatchMesh;\nclass TerrainPatchMesher;\nclass TerrainPatchMeshManager;\nclass SphericalHeightmapGenerator;\n\n#define TERRAIN_MESH_TASK_ID 6\n\n// Represents A Mesh Creation Task\nclass TerrainPatchMeshTask : public vcore::IThreadPoolTask < WorkerData > {\npublic:\n    TerrainPatchMeshTask() : vcore::IThreadPoolTask<WorkerData>(TERRAIN_MESH_TASK_ID) {}\n\n    // Initializes the task\n    void init(const TerrainPatchData* patchData,\n              TerrainPatchMesh* mesh,\n              const f32v3& startPos,\n              float width,\n              WorldCubeFace cubeFace);\n\n    // Executes the task\n    void execute(WorkerData* workerData) override;\n\nprivate:\n    f32v3 m_startPos;\n    WorldCubeFace m_cubeFace;\n    float m_width;\n    TerrainPatchMesh* m_mesh = nullptr;\n    const TerrainPatchData* m_patchData = nullptr;\n};\n\n#endif // TerrainPatchMeshTask_h__\n"
  },
  {
    "path": "SoA/TerrainPatchMesher.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TerrainPatchMesher.h\"\n\n#include \"VoxelSpaceConversions.h\"\n#include \"SphericalTerrainComponentUpdater.h\"\n#include \"SphericalHeightmapGenerator.h\"\n#include \"TerrainPatchMeshManager.h\"\n#include \"PlanetGenData.h\"\n\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/GraphicsDevice.h>\n#include <Vorb/TextureRecycler.hpp>\n\n/// Debug colors for rendering faces with unique color\nconst color3 DebugColors[6] {\n      color3(255, 0, 0), //TOP\n      color3(0, 255, 0), //LEFT\n      color3(0, 0, 255), //RIGHT\n      color3(255, 255, 0), //FRONT\n      color3(0, 255, 255), //BACK\n      color3(255, 0, 255) //BOTTOM\n};\n\nVGIndexBuffer TerrainPatchMesher::m_sharedIbo = 0; ///< Reusable CCW IBO\n\nvoid TerrainPatchMesher::generateIndices() {\n    // Loop through each quad and set indices\n    int vertIndex;\n    int index = 0;\n    int skirtIndex = PATCH_SIZE;\n    ui16 indices[PATCH_INDICES];\n\n    // Main vertices\n    for (int z = 0; z < PATCH_WIDTH - 1; z++) {\n        for (int x = 0; x < PATCH_WIDTH - 1; x++) {\n            // Compute index of back left vertex\n            vertIndex = z * PATCH_WIDTH + x;\n            // Change triangle orientation based on odd or even\n            if ((x + z) % 2) {\n                indices[index++] = vertIndex;\n                indices[index++] = vertIndex + PATCH_WIDTH;\n                indices[index++] = vertIndex + PATCH_WIDTH + 1;\n                indices[index++] = vertIndex + PATCH_WIDTH + 1;\n                indices[index++] = vertIndex + 1;\n                indices[index++] = vertIndex;\n            } else {\n                indices[index++] = vertIndex + 1;\n                indices[index++] = vertIndex;\n                indices[index++] = vertIndex + PATCH_WIDTH;\n                indices[index++] = vertIndex + PATCH_WIDTH;\n                indices[index++] = vertIndex + PATCH_WIDTH + 1;\n                indices[index++] = vertIndex + 1;\n            }\n        }\n    }\n    // Skirt vertices\n    // Top Skirt\n    for (int i = 0; i < PATCH_WIDTH - 1; i++) {\n        vertIndex = i;\n        indices[index++] = skirtIndex;\n        indices[index++] = vertIndex;\n        indices[index++] = vertIndex + 1;\n        indices[index++] = vertIndex + 1;\n        indices[index++] = skirtIndex + 1;\n        indices[index++] = skirtIndex;\n        skirtIndex++;\n    }\n    skirtIndex++; // Skip last vertex\n    // Left Skirt\n    for (int i = 0; i < PATCH_WIDTH - 1; i++) {\n        vertIndex = i * PATCH_WIDTH;\n        indices[index++] = skirtIndex;\n        indices[index++] = skirtIndex + 1;\n        indices[index++] = vertIndex + PATCH_WIDTH;\n        indices[index++] = vertIndex + PATCH_WIDTH;\n        indices[index++] = vertIndex;\n        indices[index++] = skirtIndex;\n        skirtIndex++;\n    }\n    skirtIndex++; // Skip last vertex\n    // Right Skirt\n    for (int i = 0; i < PATCH_WIDTH - 1; i++) {\n        vertIndex = i * PATCH_WIDTH + PATCH_WIDTH - 1;\n        indices[index++] = vertIndex;\n        indices[index++] = vertIndex + PATCH_WIDTH;\n        indices[index++] = skirtIndex + 1;\n        indices[index++] = skirtIndex + 1;\n        indices[index++] = skirtIndex;\n        indices[index++] = vertIndex;\n        skirtIndex++;\n    }\n    skirtIndex++;\n    // Bottom Skirt\n    for (int i = 0; i < PATCH_WIDTH - 1; i++) {\n        vertIndex = PATCH_SIZE - PATCH_WIDTH + i;\n        indices[index++] = vertIndex;\n        indices[index++] = skirtIndex;\n        indices[index++] = skirtIndex + 1;\n        indices[index++] = skirtIndex + 1;\n        indices[index++] = vertIndex + 1;\n        indices[index++] = vertIndex;\n        skirtIndex++;\n    }\n\n    vg::GpuMemory::createBuffer(m_sharedIbo);\n    vg::GpuMemory::bindBuffer(m_sharedIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(m_sharedIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER,\n                                    PATCH_INDICES * sizeof(ui16),\n                                    indices);\n}\n\nvoid TerrainPatchMesher::destroyIndices() {\n    vg::GpuMemory::freeBuffer(m_sharedIbo);\n}\n\nvoid TerrainPatchMesher::generateMeshData(TerrainPatchMesh* mesh, const PlanetGenData* planetGenData,\n                                          const f32v3& startPos, WorldCubeFace cubeFace, float width,\n                                          PlanetHeightData heightData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH],\n                                          f64v3 positionData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH]) {\n\n    assert(m_sharedIbo != 0);\n\n    m_planetGenData = planetGenData;\n    m_radius = (f32)m_planetGenData->radius;\n\n    m_isSpherical = mesh->getIsSpherical();\n    m_cubeFace = cubeFace;\n    // Grab mappings so we can rotate the 2D grid appropriately\n    if (m_isSpherical) {\n        m_coordMapping = VoxelSpaceConversions::VOXEL_TO_WORLD[(int)m_cubeFace];\n        m_startPos = startPos;\n        m_coordMults = f32v2(VoxelSpaceConversions::FACE_TO_WORLD_MULTS[(int)m_cubeFace]);\n    } else {\n        m_coordMapping = i32v3(0, 1, 2);\n        m_startPos = f32v3(startPos.x, 0.0f, startPos.z);\n        m_coordMults = f32v2(1.0f);\n    }\n    \n    f32 h;\n    // f32v3 tmpPos;\n    f32 minX = FLT_MAX, maxX = -FLT_MAX;\n    f32 minY = FLT_MAX, maxY = -FLT_MAX;\n    f32 minZ = FLT_MAX, maxZ = -FLT_MAX;\n\n    // Clear water index grid\n    memset(waterIndexGrid, 0, sizeof(waterIndexGrid));\n    memset(waterQuads, 0, sizeof(waterQuads));\n    m_waterIndex = 0;\n    m_waterIndexCount = 0;\n\n    // Loop through and set all vertex attributes\n    m_vertWidth = width / (PATCH_WIDTH - 1);\n    m_index = 0;\n\n    for (int z = 1; z < PADDED_PATCH_WIDTH - 1; z++) {\n        for (int x = 1; x < PADDED_PATCH_WIDTH - 1; x++) {\n\n            auto& v = verts[m_index];\n\n            // Set the position based on which face we are on\n            v.position = positionData[z][x];\n\n            // Set color\n            v.color = m_planetGenData->terrainTint;\n            //v.color = DebugColors[(int)mesh->m_cubeFace]; // Uncomment for unique face colors\n\n            // TODO(Ben): This is temporary edge debugging stuff\n           /* const float delta = 100.0f;\n            if (abs(v.position[m_coordMapping.x]) >= m_radius - delta\n                || abs(v.position[m_coordMapping.z]) >= m_radius - delta) {\n                v.color.r = 255;\n                v.color.g = 0;\n                v.color.b = 0;\n            }*/\n\n            // TODO(Ben): This is temporary biome debugging\n            // v.color = heightData[z][x].biome->mapColor;\n\n            // Get data from heightmap \n            h = heightData[z][x].height;\n\n            // Water indexing\n            if (h < 0) {\n                addWater(z - 1, x - 1, heightData);\n            }\n\n            // TODO(Ben): Only update when not in frustum. Use double frustum method to start loading at frustum 2 and force in frustum 1\n            v.temperature = heightData[z][x].temperature;\n            v.humidity = heightData[z][x].humidity;\n\n            // Check bounding box\n            // TODO(Ben): Worry about water too!\n            if (v.position.x < minX) minX = v.position.x;\n            if (v.position.x > maxX) maxX = v.position.x;\n            if (v.position.y < minY) minY = v.position.y;\n            if (v.position.y > maxY) maxY = v.position.y;\n            if (v.position.z < minZ) minZ = v.position.z;\n            if (v.position.z > maxZ) maxZ = v.position.z;\n\n            m_index++;\n        }\n    }\n\n    f64v3 pl;\n    f64v3 pr;\n    f64v3 pb;\n    f64v3 pf;\n\n    // Second pass for normals TODO(Ben): Padding\n    for (int z = 1; z < PADDED_PATCH_WIDTH - 1; z++) {\n        for (int x = 1; x < PADDED_PATCH_WIDTH - 1; x++) {\n            auto& v = verts[(z - 1) * PATCH_WIDTH + x - 1];\n            f64v3& p = positionData[z][x];\n            pl = positionData[z][x - 1] - p;\n            pr = positionData[z][x + 1] - p;\n            pb = positionData[z - 1][x] - p;\n            pf = positionData[z + 1][x] - p;\n            // Calculate smooth normal\n            v.normal = glm::normalize(glm::cross(pb, pl) + glm::cross(pl, pf) +\n                                      glm::cross(pf, pr) + glm::cross(pr, pb));\n        }\n    }\n\n    // Get AABB\n    mesh->m_aabbPos = f32v3(minX, minY, minZ);\n    mesh->m_aabbDims = f32v3(maxX - minX, maxY - minY, maxZ - minZ);\n    mesh->m_aabbCenter = mesh->m_aabbPos + mesh->m_aabbDims * 0.5f;\n    // Calculate bounding sphere for culling\n    mesh->m_boundingSphereRadius = glm::length(mesh->m_aabbCenter - mesh->m_aabbPos);\n    // Build the skirts for crack hiding\n    buildSkirts();\n\n    // Make all vertices relative to the aabb pos for far terrain\n    if (!m_isSpherical) {\n        for (int i = 0; i < m_index; i++) {\n            verts[i].position = f32v3(f64v3(verts[i].position) - f64v3(mesh->m_aabbPos));\n        }\n    }\n\n    mesh->m_waterIndexCount = m_waterIndexCount;\n    mesh->m_waterVertexCount = m_waterIndex;\n\n    std::vector<ui8>& data = mesh->m_meshDataBuffer;\n\n    data.resize(VERTS_SIZE * sizeof(TerrainVertex) +\n                mesh->m_waterVertexCount * sizeof(WaterVertex) +\n                mesh->m_waterIndexCount * sizeof(ui16));\n\n    // Copy buffer data\n    memcpy(data.data(), verts, VERTS_SIZE * sizeof(TerrainVertex));\n    ui32 offset = VERTS_SIZE * sizeof(TerrainVertex);\n\n    // Add water mesh\n    if (m_waterIndexCount) {\n        // Make all vertices relative to the aabb pos for far terrain\n        if (!m_isSpherical) {\n            for (int i = 0; i < m_index; i++) {\n                waterVerts[i].position -= mesh->m_aabbPos;\n            }\n        }\n        // Copy water data\n        memcpy(data.data() + offset, waterVerts, mesh->m_waterVertexCount * sizeof(WaterVertex));\n        offset += mesh->m_waterVertexCount * sizeof(WaterVertex);\n        memcpy(data.data() + offset, waterIndices, mesh->m_waterIndexCount * sizeof(ui16));\n    }\n}\n\nvoid TerrainPatchMesher::uploadMeshData(TerrainPatchMesh* mesh) {\n    // Make VAO\n    glGenVertexArrays(1, &mesh->m_vao);\n    glBindVertexArray(mesh->m_vao);\n\n    ui32 offset;\n\n    // Generate the buffers and upload data\n    vg::GpuMemory::createBuffer(mesh->m_vbo);\n    vg::GpuMemory::bindBuffer(mesh->m_vbo, vg::BufferTarget::ARRAY_BUFFER);\n    vg::GpuMemory::uploadBufferData(mesh->m_vbo, vg::BufferTarget::ARRAY_BUFFER,\n                                    VERTS_SIZE * sizeof(TerrainVertex),\n                                    mesh->m_meshDataBuffer.data());\n    offset = VERTS_SIZE * sizeof(TerrainVertex);\n\n    // Reusable IBO\n    vg::GpuMemory::bindBuffer(m_sharedIbo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n\n    // Vertex attribute pointers\n    glEnableVertexAttribArray(0);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,\n                          sizeof(TerrainVertex),\n                          offsetptr(TerrainVertex, position));\n    glEnableVertexAttribArray(1);\n    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,\n                          sizeof(TerrainVertex),\n                          offsetptr(TerrainVertex, normal));\n    glEnableVertexAttribArray(2);\n    glVertexAttribPointer(2, 3, GL_UNSIGNED_BYTE, GL_TRUE,\n                          sizeof(TerrainVertex),\n                          offsetptr(TerrainVertex, color));\n    glEnableVertexAttribArray(3);\n    glVertexAttribPointer(3, 2, GL_UNSIGNED_BYTE, GL_TRUE,\n                          sizeof(TerrainVertex),\n                          offsetptr(TerrainVertex, temperature));\n\n    // Add water mesh\n    if (mesh->m_waterIndexCount) {\n\n        // Make VAO\n        glGenVertexArrays(1, &mesh->m_wvao);\n        glBindVertexArray(mesh->m_wvao);\n\n        vg::GpuMemory::createBuffer(mesh->m_wvbo);\n        vg::GpuMemory::bindBuffer(mesh->m_wvbo, vg::BufferTarget::ARRAY_BUFFER);\n        vg::GpuMemory::uploadBufferData(mesh->m_wvbo, vg::BufferTarget::ARRAY_BUFFER,\n                                        mesh->m_waterVertexCount * sizeof(WaterVertex),\n                                        mesh->m_meshDataBuffer.data() + offset);\n        offset += mesh->m_waterVertexCount * sizeof(WaterVertex);\n        vg::GpuMemory::createBuffer(mesh->m_wibo);\n        vg::GpuMemory::bindBuffer(mesh->m_wibo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER);\n        vg::GpuMemory::uploadBufferData(mesh->m_wibo, vg::BufferTarget::ELEMENT_ARRAY_BUFFER,\n                                        mesh->m_waterIndexCount * sizeof(ui16),\n                                        mesh->m_meshDataBuffer.data() + offset);\n        // Vertex attribute pointers\n        glEnableVertexAttribArray(0);\n        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,\n                              sizeof(WaterVertex),\n                              offsetptr(WaterVertex, position));\n        glEnableVertexAttribArray(1);\n        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,\n                              sizeof(WaterVertex),\n                              offsetptr(WaterVertex, tangent));\n        glEnableVertexAttribArray(2);\n        glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE,\n                              sizeof(WaterVertex),\n                              offsetptr(WaterVertex, color));\n        glEnableVertexAttribArray(3);\n        glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE,\n                              sizeof(WaterVertex),\n                              offsetptr(WaterVertex, depth));\n    }\n    // Clear the data\n    std::vector<ui8>().swap(mesh->m_meshDataBuffer);\n    glBindVertexArray(0);\n}\n\nvoid TerrainPatchMesher::buildSkirts() {\n    const float SKIRT_DEPTH = m_vertWidth * 3.0f;\n    // Top Skirt\n    for (int i = 0; i < PATCH_WIDTH; i++) {\n        auto& v = verts[m_index];\n        // Copy the vertices from the top edge\n        v = verts[i];\n        // Extrude downward\n        if (m_isSpherical) {\n            float len = glm::length(v.position) - SKIRT_DEPTH;\n            v.position = glm::normalize(v.position) * len;\n        } else {\n            v.position.y -= SKIRT_DEPTH;\n        }\n        m_index++;\n    }\n    // Left Skirt\n    for (int i = 0; i < PATCH_WIDTH; i++) {\n        auto& v = verts[m_index];\n        // Copy the vertices from the left edge\n        v = verts[i * PATCH_WIDTH];\n        // Extrude downward\n        if (m_isSpherical) {\n            float len = glm::length(v.position) - SKIRT_DEPTH;\n            v.position = glm::normalize(v.position) * len;\n        } else {\n            v.position.y -= SKIRT_DEPTH;\n        }\n        m_index++;\n    }\n    // Right Skirt\n    for (int i = 0; i < PATCH_WIDTH; i++) {\n        auto& v = verts[m_index];\n        // Copy the vertices from the right edge\n        v = verts[i * PATCH_WIDTH + PATCH_WIDTH - 1];\n        // Extrude downward\n        if (m_isSpherical) {\n            float len = glm::length(v.position) - SKIRT_DEPTH;\n            v.position = glm::normalize(v.position) * len;\n        } else {\n            v.position.y -= SKIRT_DEPTH;\n        }\n        m_index++;\n    }\n    // Bottom Skirt\n    for (int i = 0; i < PATCH_WIDTH; i++) {\n        auto& v = verts[m_index];\n        // Copy the vertices from the bottom edge\n        v = verts[PATCH_SIZE - PATCH_WIDTH + i];\n        // Extrude downward\n        if (m_isSpherical) {\n            float len = glm::length(v.position) - SKIRT_DEPTH;\n            v.position = glm::normalize(v.position) * len;\n        } else {\n            v.position.y -= SKIRT_DEPTH;\n        }\n        m_index++;\n    }\n}\n\nvoid TerrainPatchMesher::addWater(int z, int x, PlanetHeightData heightData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH]) {\n    // Try add all adjacent vertices if needed\n    tryAddWaterVertex(z - 1, x - 1, heightData);\n    tryAddWaterVertex(z - 1, x, heightData);\n    tryAddWaterVertex(z - 1, x + 1, heightData);\n    tryAddWaterVertex(z, x - 1, heightData);\n    tryAddWaterVertex(z, x, heightData);\n    tryAddWaterVertex(z, x + 1, heightData);\n    tryAddWaterVertex(z + 1, x - 1, heightData);\n    tryAddWaterVertex(z + 1, x, heightData);\n    tryAddWaterVertex(z + 1, x + 1, heightData);\n\n    // Try add quads\n    tryAddWaterQuad(z - 1, x - 1);\n    tryAddWaterQuad(z - 1, x);\n    tryAddWaterQuad(z, x - 1);\n    tryAddWaterQuad(z, x);\n}\n\nvoid TerrainPatchMesher::tryAddWaterVertex(int z, int x, PlanetHeightData heightData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH]) {\n    // TEMPORARY? Add slight offset so we don't need skirts\n    f32 mvw = m_vertWidth * 1.005f;\n    // const f32 UV_SCALE = 0.04f;\n\n    if (z < 0 || x < 0 || z >= PATCH_WIDTH || x >= PATCH_WIDTH) return;\n    if (waterIndexGrid[z][x] == 0) {\n        waterIndexGrid[z][x] = m_waterIndex + 1;\n        auto& v = waterVerts[m_waterIndex];\n        // Set the position based on which face we are on\n        v.position[m_coordMapping.x] = (x * mvw + m_startPos.x) * m_coordMults.x;\n        v.position[m_coordMapping.y] = m_startPos.y;\n        v.position[m_coordMapping.z] = (z * mvw + m_startPos.z) * m_coordMults.y;\n\n        // Spherify it!\n        // TODO(Ben): Use normal data\n        f32v3 normal;\n        if (m_isSpherical) {\n            normal = glm::normalize(v.position);\n            v.position = normal * m_radius;\n        } else {\n            const i32v3& trueMapping = VoxelSpaceConversions::VOXEL_TO_WORLD[(int)m_cubeFace];\n            f32v3 tmpPos;\n            tmpPos[trueMapping.x] = v.position.x;\n            tmpPos[trueMapping.y] = m_radius * (f32)VoxelSpaceConversions::FACE_Y_MULTS[(int)m_cubeFace];\n            tmpPos[trueMapping.z] = v.position.z;\n            normal = glm::normalize(tmpPos);\n        }\n\n        f32 d = heightData[z + 1][x + 1].height * (f32)M_PER_VOXEL;\n        if (d < 0) {\n            v.depth = -d;\n        } else {\n            v.depth = 0;\n        }\n\n        v.temperature = heightData[z + 1][x + 1].temperature;\n\n        // Compute tangent\n        f32v3 tmpPos;\n        tmpPos[m_coordMapping.x] = ((x + 1) * mvw + m_startPos.x) * m_coordMults.x;\n        tmpPos[m_coordMapping.y] = m_startPos.y;\n        tmpPos[m_coordMapping.z] = (z * mvw + m_startPos.z) * m_coordMults.y;\n        tmpPos = glm::normalize(tmpPos) * m_radius;\n        v.tangent = glm::normalize(tmpPos - v.position);\n\n        // Make sure tangent is orthogonal\n        f32v3 binormal = glm::normalize(glm::cross(glm::normalize(v.position), v.tangent));\n        v.tangent = glm::normalize(glm::cross(binormal, glm::normalize(v.position)));\n\n        v.color = m_planetGenData->liquidTint;\n\n        // TODO(Ben): This is temporary edge debugging stuff\n        const float delta = 100.0f;\n        if (abs(v.position[m_coordMapping.x]) >= m_radius - delta\n            || abs(v.position[m_coordMapping.z]) >= m_radius - delta) {\n            v.color.r = 255;\n            v.color.g = 0;\n            v.color.b = 0;\n        }\n        m_waterIndex++;\n    }\n}\n\nvoid TerrainPatchMesher::tryAddWaterQuad(int z, int x) {\n    if (z < 0 || x < 0 || z >= PATCH_WIDTH - 1 || x >= PATCH_WIDTH - 1) return;\n    if (!waterQuads[z][x]) {\n        waterQuads[z][x] = true;\n        waterIndices[m_waterIndexCount++] = waterIndexGrid[z][x] - 1;\n        waterIndices[m_waterIndexCount++] = waterIndexGrid[z + 1][x] - 1;\n        waterIndices[m_waterIndexCount++] = waterIndexGrid[z + 1][x + 1] - 1;\n        waterIndices[m_waterIndexCount++] = waterIndexGrid[z + 1][x + 1] - 1;\n        waterIndices[m_waterIndexCount++] = waterIndexGrid[z][x + 1] - 1;\n        waterIndices[m_waterIndexCount++] = waterIndexGrid[z][x] - 1;\n    }\n}\n"
  },
  {
    "path": "SoA/TerrainPatchMesher.h",
    "content": "///\n/// TerrainPatchMesher.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 3 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Creates terrain patch meshes\n///\n\n#pragma once\n\n#ifndef TerrainPatchMesher_h__\n#define TerrainPatchMesher_h__\n\n#include <Vorb/graphics/gtypes.h>\n#include \"TerrainPatchMesh.h\"\n#include \"PlanetHeightData.h\"\n\nstruct PlanetGenData;\nclass TerrainPatchMeshManager;\n\nclass TerrainPatchMesher {\npublic:\n    /// Generates shared index buffer.\n    static void generateIndices();\n    static void destroyIndices();\n\n    /// Generates mesh using heightmap\n    void generateMeshData(TerrainPatchMesh* mesh, const PlanetGenData* planetGenData,\n                          const f32v3& startPos, WorldCubeFace cubeFace,\n                          float width, PlanetHeightData heightData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH],\n                          f64v3 positionData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH]);\n\n    static void uploadMeshData(TerrainPatchMesh* mesh);\n\n    static const int VERTS_SIZE = PATCH_SIZE + PATCH_WIDTH * 4; ///< Number of vertices per patch\nprivate:\n\n    /// Builds the skirts for a patch\n    void buildSkirts();\n\n    /// Adds water at a given point\n    /// @param z: Z position\n    /// @Param x: X position\n    /// @param heightData: The heightmap data\n    void addWater(int z, int x, PlanetHeightData heightData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH]);\n\n    /// Tries to add a water vertex at a given spot if one doesn't exist\n    /// @param z: Z position\n    /// @param x: X position\n    /// @param heightData: The heightmap data\n    void tryAddWaterVertex(int z, int x, PlanetHeightData heightData[PADDED_PATCH_WIDTH][PADDED_PATCH_WIDTH]);\n\n    /// Tries to add a quad at a given spot if one doesnt exist\n    /// @param z: Z position\n    /// @param x: X position\n    void tryAddWaterQuad(int z, int x);\n\n    static VGIndexBuffer m_sharedIbo; ///< Reusable CCW IBO\n\n    // PATCH_WIDTH * 4 is for skirts\n\n    TerrainVertex verts[VERTS_SIZE]; ///< Vertices for terrain mesh\n    WaterVertex waterVerts[VERTS_SIZE]; ///< Vertices for water mesh\n    ui16 waterIndexGrid[PATCH_WIDTH][PATCH_WIDTH]; ///< Caches water indices for reuse\n    ui16 waterIndices[PATCH_INDICES]; ///< Buffer of indices to upload\n    bool waterQuads[PATCH_WIDTH - 1][PATCH_WIDTH - 1]; ///< True when a quad is present at a spot\n\n    const PlanetGenData* m_planetGenData = nullptr; ///< Planetary data\n//    TerrainPatchMeshManager* m_meshManager = nullptr; ///< Manages the patch meshes\n\n    /// Meshing helper vars\n    int m_index;\n    int m_waterIndex;\n    int m_waterIndexCount;\n    f32 m_vertWidth;\n    f32 m_radius;\n    i32v3 m_coordMapping;\n    f32v3 m_startPos;\n    f32v2 m_coordMults;\n    bool m_isSpherical;\n    WorldCubeFace m_cubeFace;\n};\n\n#endif // TerrainPatchMesher_h__\n"
  },
  {
    "path": "SoA/TestBiomeScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestBiomeScreen.h\"\n\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/colors.h>\n\n#include \"App.h\"\n#include \"ChunkRenderer.h\"\n#include \"DevConsole.h\"\n#include \"InputMapper.h\"\n#include \"Inputs.h\"\n#include \"LoadTaskBlockData.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n#include \"SoaEngine.h\"\n#include \"SoAState.h\"\n\n#ifdef DEBUG\n#define HORIZONTAL_CHUNKS 26\n#define VERTICAL_CHUNKS 4\n#else\n\n#define HORIZONTAL_CHUNKS 26\n#define VERTICAL_CHUNKS 20\n#endif\n\nTestBiomeScreen::TestBiomeScreen(const App* app, CommonState* state) :\nIAppScreen<App>(app),\nm_commonState(state),\nm_soaState(m_commonState->state),\nm_blockArrayRecycler(1000) {\n\n}\n\ni32 TestBiomeScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestBiomeScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestBiomeScreen::build() {\n\n}\n\nvoid TestBiomeScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n\n}\n\nvoid TestBiomeScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    // Init spritebatch and font\n    m_sb.init();\n    m_font.init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n    // Init game state\n    SoaEngine::initState(m_commonState->state);\n    // Init access\n    m_accessor.init(&m_allocator);\n    // Init renderer\n    m_renderer.init();\n\n    { // Init post processing\n        Array<vg::GBufferAttachment> attachments;\n        vg::GBufferAttachment att[2];\n        // Color\n        att[0].format = vg::TextureInternalFormat::RGBA16F;\n        att[0].pixelFormat = vg::TextureFormat::RGBA;\n        att[0].pixelType = vg::TexturePixelType::UNSIGNED_BYTE;\n        att[0].number = 1;\n        // Normals\n        att[1].format = vg::TextureInternalFormat::RGBA16F;\n        att[1].pixelFormat = vg::TextureFormat::RGBA;\n        att[1].pixelType = vg::TexturePixelType::UNSIGNED_BYTE;\n        att[1].number = 2;\n        m_hdrTarget.setSize(m_commonState->window->getWidth(), m_commonState->window->getHeight());\n        m_hdrTarget.init(Array<vg::GBufferAttachment>(att, 2), vg::TextureInternalFormat::RGBA8).initDepth();\n\n        // Swapchain\n        m_swapChain.init(m_commonState->window->getWidth(), m_commonState->window->getHeight(), vg::TextureInternalFormat::RGBA16F);\n\n        // Init the FullQuadVBO\n        m_commonState->quad.init();\n\n        // SSAO\n        m_ssaoStage.init(m_commonState->window, m_commonState->loadContext);\n        m_ssaoStage.load(m_commonState->loadContext);\n        m_ssaoStage.hook(&m_commonState->quad, m_commonState->window->getWidth(), m_commonState->window->getHeight());\n\n        // HDR\n        m_hdrStage.init(m_commonState->window, m_commonState->loadContext);\n        m_hdrStage.load(m_commonState->loadContext);\n        m_hdrStage.hook(&m_commonState->quad);\n    }\n\n    // Load test planet\n    PlanetGenLoader planetLoader;\n    m_iom.setSearchDirectory(\"StarSystems/Trinity/\");\n    planetLoader.init(&m_iom);\n    m_genData = planetLoader.loadPlanetGenData(\"Moons/Aldrin/terrain_gen.yml\");\n    if (m_genData->terrainColorPixels.data) {\n        m_soaState->clientState.blockTextures->setColorMap(\"biome\", &m_genData->terrainColorPixels);\n    }\n\n    // Load blocks\n    LoadTaskBlockData blockLoader(&m_soaState->blocks,\n                                  &m_soaState->clientState.blockTextureLoader,\n                                  &m_commonState->loadContext);\n    blockLoader.load();\n\n    // Uploads all the needed textures\n    m_soaState->clientState.blockTextures->update();\n    \n    m_genData->radius = 4500.0;\n    \n    // Set blocks\n    SoaEngine::initVoxelGen(m_genData, m_soaState->blocks);\n    \n    m_chunkGenerator.init(m_genData);\n\n    initHeightData();\n    initChunks();\n\n    printf(\"Generating Meshes...\\n\");\n    // Create all chunk meshes\n    m_mesher.init(&m_soaState->blocks);\n    for (auto& cv : m_chunks) {\n        cv.chunkMesh = m_mesher.easyCreateChunkMesh(cv.chunk, MeshTaskType::DEFAULT);\n    }\n\n    { // Init the camera\n        m_camera.init(m_commonState->window->getAspectRatio());\n        m_camera.setPosition(f64v3(16.0, 17.0, 33.0));\n        m_camera.setDirection(f32v3(0.0f, 0.0f, -1.0f));\n        m_camera.setRight(f32v3(1.0f, 0.0f, 0.0f));\n        m_camera.setUp(f32v3(0.0f, 1.0f, 0.0f));\n    }\n\n    initInput();\n\n    // Initialize dev console\n    vui::GameWindow* window = m_commonState->window;\n    m_devConsoleView.init(&DevConsole::getInstance(), 5,\n                          f32v2(20.0f, window->getHeight() - 400.0f),\n                          window->getWidth() - 40.0f);\n\n    // Set GL state\n    glEnable(GL_DEPTH_TEST);\n    glEnable(GL_CULL_FACE);\n    glClearDepth(1.0);\n    printf(\"Done.\");\n}\n\nvoid TestBiomeScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    for (auto& cv : m_chunks) {\n        m_mesher.freeChunkMesh(cv.chunkMesh);\n    }\n    m_hdrTarget.dispose();\n    m_swapChain.dispose();\n\n    m_devConsoleView.dispose();\n}\n\nvoid TestBiomeScreen::update(const vui::GameTime& gameTime) {\n    f32 speed = 10.0f;\n    if (m_movingFast) speed *= 5.0f;\n    if (m_movingForward) {\n        f32v3 offset = m_camera.getDirection() * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingBack) {\n        f32v3 offset = m_camera.getDirection() * -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingLeft) {\n        f32v3 offset = m_camera.getRight() * -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingRight) {\n        f32v3 offset = m_camera.getRight() * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingUp) {\n        f32v3 offset = f32v3(0, 1, 0) * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingDown) {\n        f32v3 offset = f32v3(0, 1, 0) *  -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    m_camera.update();\n}\n\nvoid TestBiomeScreen::draw(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Bind the FBO\n    m_hdrTarget.useGeometry();\n\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n    if (m_wireFrame) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n\n    // Opaque\n    m_renderer.beginOpaque(m_soaState->clientState.blockTextures->getAtlasTexture(),\n                           f32v3(0.0f, 0.0f, -1.0f), f32v3(1.0f),\n                           f32v3(0.3f));\n    for (auto& vc : m_chunks) {\n        if (m_camera.getFrustum().sphereInFrustum(f32v3(vc.chunkMesh->position + f64v3(CHUNK_WIDTH / 2) - m_camera.getPosition()), CHUNK_DIAGONAL_LENGTH)) {\n            vc.inFrustum = true;\n            m_renderer.drawOpaque(vc.chunkMesh, m_camera.getPosition(), m_camera.getViewProjectionMatrix());\n        } else {\n            vc.inFrustum = false;\n        }\n    }\n    // Cutout\n    m_renderer.beginCutout(m_soaState->clientState.blockTextures->getAtlasTexture(),\n                           f32v3(0.0f, 0.0f, -1.0f), f32v3(1.0f),\n                           f32v3(0.3f));\n    for (auto& vc : m_chunks) {\n        if (vc.inFrustum) {\n            m_renderer.drawCutout(vc.chunkMesh, m_camera.getPosition(), m_camera.getViewProjectionMatrix());\n        }\n    }\n\n    m_renderer.end();\n\n    if (m_wireFrame) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\n    // Post processing\n    m_swapChain.reset(0, m_hdrTarget.getGeometryID(), m_hdrTarget.getGeometryTexture(0), soaOptions.get(OPT_MSAA).value.i > 0, false);\n\n    // Render SSAO\n    m_ssaoStage.set(m_hdrTarget.getDepthTexture(), m_hdrTarget.getGeometryTexture(1), m_hdrTarget.getGeometryTexture(0), m_swapChain.getCurrent().getID());\n    m_ssaoStage.render(&m_camera);\n    m_swapChain.swap();\n    m_swapChain.use(0, false);\n\n    // Draw to backbuffer for the last effect\n    // TODO(Ben): Do we really need to clear depth here...\n    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n    glDrawBuffer(GL_BACK);\n    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, m_hdrTarget.getDepthTexture());\n    m_hdrStage.render();\n\n    // Draw UI\n    char buf[256];\n    sprintf(buf, \"FPS: %.1f\", m_app->getFps());\n    m_sb.begin();\n    m_sb.drawString(&m_font, buf, f32v2(30.0f), f32v2(1.0f), color::White);\n    m_sb.end();\n    m_sb.render(f32v2(m_commonState->window->getViewportDims()));\n    vg::DepthState::FULL.set(); // Have to restore depth\n\n    // Draw dev console\n    m_devConsoleView.update(0.01f);\n    m_devConsoleView.render(m_game->getWindow().getViewportDims());\n}\n\nvoid TestBiomeScreen::initHeightData() {\n    printf(\"Generating height data...\\n\");\n    m_heightData.resize(HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS);\n    // Init height data\n    m_heightGenerator.init(m_genData);\n    for (int z = 0; z < HORIZONTAL_CHUNKS; z++) {\n        for (int x = 0; x < HORIZONTAL_CHUNKS; x++) {\n            auto& hd = m_heightData[z * HORIZONTAL_CHUNKS + x];\n            for (int i = 0; i < CHUNK_WIDTH; i++) {\n                for (int j = 0; j < CHUNK_WIDTH; j++) {\n                    VoxelPosition2D pos;\n                    pos.pos.x = x * CHUNK_WIDTH + j + 3000;\n                    pos.pos.y = z * CHUNK_WIDTH + i + 3000;\n                    PlanetHeightData& data = hd.heightData[i * CHUNK_WIDTH + j];\n                    m_heightGenerator.generateHeightData(data, pos);\n                    data.temperature = 128;\n                    data.humidity = 128;\n                }\n            }\n        }\n    }\n\n    // Get center height\n    f32 cHeight = m_heightData[HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS / 2].heightData[CHUNK_LAYER / 2].height;\n    // Center the heightmap\n    for (auto& hd : m_heightData) {\n        for (int i = 0; i < CHUNK_LAYER; i++) {\n            hd.heightData[i].height -= cHeight;\n        }\n    }\n}\n\n\nvoid TestBiomeScreen::initChunks() {\n    printf(\"Generating chunks...\\n\");\n    m_chunks.resize(HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS * VERTICAL_CHUNKS);\n\n    // Generate chunk data\n    for (size_t i = 0; i < m_chunks.size(); i++) {\n        ChunkPosition3D pos;\n        i32v3 gridPosition;\n        gridPosition.x = i % HORIZONTAL_CHUNKS;\n        gridPosition.y = i / (HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS);\n        gridPosition.z = (i % (HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS)) / HORIZONTAL_CHUNKS;\n        // Center position about origin\n        pos.pos.x = gridPosition.x - HORIZONTAL_CHUNKS / 2;\n        pos.pos.y = gridPosition.y - VERTICAL_CHUNKS / 4;\n        pos.pos.z = gridPosition.z - HORIZONTAL_CHUNKS / 2;\n        // Init parameters\n        ChunkID id(pos.x, pos.y, pos.z);\n        m_chunks[i].chunk = m_accessor.acquire(id);\n        m_chunks[i].chunk->init(WorldCubeFace::FACE_TOP);\n        m_chunks[i].gridPosition = gridPosition;\n        m_chunks[i].chunk->gridData = &m_heightData[i % (HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS)];\n        // Generate the chunk\n        m_chunkGenerator.generateChunk(m_chunks[i].chunk, m_chunks[i].chunk->gridData->heightData);\n        // Decompress to flat array\n        m_chunks[i].chunk->blocks.setArrayRecycler(&m_blockArrayRecycler);\n        m_chunks[i].chunk->blocks.changeState(vvox::VoxelStorageState::FLAT_ARRAY, m_chunks[i].chunk->dataMutex);\n    }\n\n    // Generate flora\n    std::vector<FloraNode> lNodes;\n    std::vector<FloraNode> wNodes;\n    // TODO(Ben): I know this is ugly\n    PreciseTimer t1;\n    t1.start();\n    for (size_t i = 0; i < m_chunks.size(); i++) {\n        Chunk* chunk = m_chunks[i].chunk;\n        m_floraGenerator.generateChunkFlora(chunk, m_heightData[i % (HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS)].heightData, lNodes, wNodes);\n        for (auto& node : wNodes) {\n            i32v3 gridPos = m_chunks[i].gridPosition;\n            gridPos.x += FloraGenerator::getChunkXOffset(node.chunkOffset);\n            gridPos.y += FloraGenerator::getChunkYOffset(node.chunkOffset);\n            gridPos.z += FloraGenerator::getChunkZOffset(node.chunkOffset);\n            if (gridPos.x >= 0 && gridPos.y >= 0 && gridPos.z >= 0\n                && gridPos.x < HORIZONTAL_CHUNKS && gridPos.y < VERTICAL_CHUNKS && gridPos.z < HORIZONTAL_CHUNKS) {\n                Chunk* chunk = m_chunks[gridPos.x + gridPos.y * HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS + gridPos.z * HORIZONTAL_CHUNKS].chunk;\n                chunk->blocks.set(node.blockIndex, node.blockID);\n            }\n        }\n        for (auto& node : lNodes) {\n            i32v3 gridPos = m_chunks[i].gridPosition;\n            gridPos.x += FloraGenerator::getChunkXOffset(node.chunkOffset);\n            gridPos.y += FloraGenerator::getChunkYOffset(node.chunkOffset);\n            gridPos.z += FloraGenerator::getChunkZOffset(node.chunkOffset);\n            if (gridPos.x >= 0 && gridPos.y >= 0 && gridPos.z >= 0\n                && gridPos.x < HORIZONTAL_CHUNKS && gridPos.y < VERTICAL_CHUNKS && gridPos.z < HORIZONTAL_CHUNKS) {\n                Chunk* chunk = m_chunks[gridPos.x + gridPos.y * HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS + gridPos.z * HORIZONTAL_CHUNKS].chunk;\n                if (chunk->blocks.get(node.blockIndex) == 0) {\n                    chunk->blocks.set(node.blockIndex, node.blockID);\n                }\n            }\n        }\n        std::vector<ui16>().swap(chunk->floraToGenerate);\n        lNodes.clear();\n        wNodes.clear();\n    }\n    printf(\"Tree Gen Time %lf\\n\", t1.stop());\n\n#define GET_INDEX(x, y, z) ((x) + (y) * HORIZONTAL_CHUNKS * HORIZONTAL_CHUNKS + (z) * HORIZONTAL_CHUNKS)\n    \n    // Set neighbor pointers\n    for (int y = 0; y < VERTICAL_CHUNKS; y++) {\n        for (int z = 0; z < HORIZONTAL_CHUNKS; z++) {\n            for (int x = 0; x < HORIZONTAL_CHUNKS; x++) {\n                Chunk* chunk = m_chunks[GET_INDEX(x, y, z)].chunk;\n                // TODO(Ben): Release these too.\n                if (x > 0) {\n                    chunk->neighbor.left = m_chunks[GET_INDEX(x - 1, y, z)].chunk.acquire();\n                }\n                if (x < HORIZONTAL_CHUNKS - 1) {\n                    chunk->neighbor.right = m_chunks[GET_INDEX(x + 1, y, z)].chunk.acquire();\n                }\n                if (y > 0) {\n                    chunk->neighbor.bottom = m_chunks[GET_INDEX(x, y - 1, z)].chunk.acquire();\n                }\n                if (y < VERTICAL_CHUNKS - 1) {\n                    chunk->neighbor.top = m_chunks[GET_INDEX(x, y + 1, z)].chunk.acquire();\n                }\n                if (z > 0) {\n                    chunk->neighbor.back = m_chunks[GET_INDEX(x, y, z - 1)].chunk.acquire();\n                }\n                if (z < HORIZONTAL_CHUNKS - 1) {\n                    chunk->neighbor.front = m_chunks[GET_INDEX(x, y, z + 1)].chunk.acquire();\n                }\n            }\n        }\n    }\n}\n\nvoid TestBiomeScreen::initInput() {\n\n    m_inputMapper = new InputMapper;\n    initInputs(m_inputMapper);\n\n    m_mouseButtons[0] = false;\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onMotion, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseMotionEvent& e) {\n        if (m_mouseButtons[0]) {\n            m_camera.rotateFromMouseAbsoluteUp(-e.dx, -e.dy, 0.01f, true);\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::LEFT) m_mouseButtons[0] = !m_mouseButtons[0];\n        if (m_mouseButtons[0]) {\n            SDL_SetRelativeMouseMode(SDL_TRUE);\n        }\n        else {\n            SDL_SetRelativeMouseMode(SDL_FALSE);\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        PlanetGenLoader planetLoader;\n        switch (e.keyCode) {\n            case VKEY_W:\n                m_movingForward = true;\n                break;\n            case VKEY_S:\n                m_movingBack = true;\n                break;\n            case VKEY_A:\n                m_movingLeft = true;\n                break;\n            case VKEY_D:\n                m_movingRight = true;\n                break;\n            case VKEY_SPACE:\n                m_movingUp = true;\n                break;\n            case VKEY_LSHIFT:\n                m_movingFast = true;\n                break;\n            case VKEY_M:\n                m_wireFrame = !m_wireFrame;\n                break;\n            case VKEY_LEFT:\n                /*    if (m_activeChunk == 0) {\n                        m_activeChunk = m_chunks.size() - 1;\n                        } else {\n                        m_activeChunk--;\n                        }*/\n                break;\n            case VKEY_RIGHT:\n                /* m_activeChunk++;\n                 if (m_activeChunk >= (int)m_chunks.size()) m_activeChunk = 0;*/\n                break;\n            case VKEY_F10:\n                // Reload meshes\n                // TODO(Ben): Destroy meshes\n                for (auto& cv : m_chunks) {\n                    m_mesher.freeChunkMesh(cv.chunkMesh);\n                    cv.chunkMesh = m_mesher.easyCreateChunkMesh(cv.chunk, MeshTaskType::DEFAULT);\n                }\n                break;\n            case VKEY_F11:\n                // Reload shaders\n                m_renderer.dispose();\n                m_renderer.init();\n                m_ssaoStage.reloadShaders();\n                break;\n            case VKEY_F12:\n                // Reload world\n                delete m_genData;\n                planetLoader.init(&m_iom);\n                m_genData = planetLoader.loadPlanetGenData(\"Planets/Aldrin/terrain_gen.yml\");\n                m_genData->radius = 4500.0;\n\n                // Set blocks\n                SoaEngine::initVoxelGen(m_genData, m_soaState->blocks);\n\n                m_chunkGenerator.init(m_genData);\n\n                for (auto& cv : m_chunks) {\n                    m_mesher.freeChunkMesh(cv.chunkMesh);\n                    cv.chunk.release();\n                }\n\n                initHeightData();\n                initChunks();\n\n                printf(\"Generating Meshes...\\n\");\n                // Create all chunk meshes\n                m_mesher.init(&m_soaState->blocks);\n                for (auto& cv : m_chunks) {\n                    cv.chunkMesh = m_mesher.easyCreateChunkMesh(cv.chunk, MeshTaskType::DEFAULT);\n                }\n                break;\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        switch (e.keyCode) {\n            case VKEY_W:\n                m_movingForward = false;\n                break;\n            case VKEY_S:\n                m_movingBack = false;\n                break;\n            case VKEY_A:\n                m_movingLeft = false;\n                break;\n            case VKEY_D:\n                m_movingRight = false;\n                break;\n            case VKEY_SPACE:\n                m_movingUp = false;\n                break;\n            case VKEY_LSHIFT:\n                m_movingFast = false;\n                break;\n        }\n    });\n\n    // Dev console\n    m_hooks.addAutoHook(m_inputMapper->get(INPUT_DEV_CONSOLE).downEvent, [](Sender s VORB_MAYBE_UNUSED, ui32 a VORB_MAYBE_UNUSED) {\n        DevConsole::getInstance().toggleFocus();\n    });\n\n    m_inputMapper->startInput();\n}\n"
  },
  {
    "path": "SoA/TestBiomeScreen.h",
    "content": "#include <Vorb/Event.hpp>\n#include <Vorb/graphics/GBuffer.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/RTSwapChain.hpp>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/FixedSizeArrayRecycler.hpp>\n\n#include \"BlockPack.h\"\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"ChunkAllocator.h\"\n#include \"ChunkMesher.h\"\n#include \"ChunkRenderer.h\"\n#include \"CommonState.h\"\n#include \"DevConsoleView.h\"\n#include \"FloraGenerator.h\"\n#include \"HdrRenderStage.h\"\n#include \"SsaoRenderStage.h\"\n#include \"SphericalHeightmapGenerator.h\"\n\nclass InputMapper;\n\nclass TestBiomeScreen : public vui::IAppScreen < App > {\npublic:\n    TestBiomeScreen(const App* app, CommonState* state);\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    i32 getNextScreen() const override;\n    i32 getPreviousScreen() const override;\n    void build() override;\n    void destroy(const vui::GameTime& gameTime) override;\n    void onEntry(const vui::GameTime& gameTime) override;\n    void onExit(const vui::GameTime& gameTime) override;\n    void update(const vui::GameTime& gameTime) override;\n    void draw(const vui::GameTime& gameTime) override;\nprivate:\n    void initHeightData();\n    void initChunks();\n    void initInput();\n\n    struct ViewableChunk {\n        ChunkHandle chunk;\n        ChunkMesh* chunkMesh;\n        i32v3 gridPosition;\n        bool inFrustum;\n    };\n\n    AutoDelegatePool m_hooks; ///< Input hooks reservoir\n    Camera m_camera;\n    BlockPack m_blocks; ///< Block data\n    CommonState* m_commonState;\n    SoaState* m_soaState;\n    ChunkRenderer m_renderer;\n    ChunkMesher m_mesher;\n    ProceduralChunkGenerator m_chunkGenerator;\n    SphericalHeightmapGenerator m_heightGenerator;\n    FloraGenerator m_floraGenerator;\n    PlanetGenData* m_genData = nullptr;\n    vio::IOManager m_iom;\n    PagedChunkAllocator m_allocator;\n    ChunkAccessor m_accessor;\n\n    vg::SpriteBatch m_sb;\n    vg::SpriteFont m_font;\n\n    std::vector <ViewableChunk> m_chunks;\n    std::vector <ChunkGridData> m_heightData;\n    vcore::FixedSizeArrayRecycler<CHUNK_SIZE, ui16> m_blockArrayRecycler;\n\n    vg::GBuffer m_hdrTarget; ///< Framebuffer needed for the HDR rendering\n    vg::RTSwapChain<2> m_swapChain; ///< Swap chain of framebuffers used for post-processing\n\n    SSAORenderStage m_ssaoStage;\n    HdrRenderStage m_hdrStage;\n\n    DevConsoleView m_devConsoleView;\n\n    InputMapper* m_inputMapper = nullptr;\n\n    bool m_wireFrame = false;\n    bool m_mouseButtons[2];\n    bool m_movingForward = false;\n    bool m_movingBack = false;\n    bool m_movingLeft = false;\n    bool m_movingRight = false;\n    bool m_movingUp = false;\n    bool m_movingDown = false;\n    bool m_movingFast = false;\n};"
  },
  {
    "path": "SoA/TestBlockViewScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestBlockViewScreen.h\"\n\n#include <Vorb/colors.h>\n#include <Vorb/graphics/GLStates.h>\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/Random.h>\n#include <Vorb/Timing.h>\n#include <Vorb/voxel/VoxelMesherCulled.h>\n\n#include \"BlockLoader.h\"\n\n#include <glm/gtx/transform.hpp>\n#include <glm/gtc/matrix_transform.hpp>\n\n#ifdef _MSC_VER\n#pragma region Simple shader code\n#endif// _MSC_VER\n\nconst cString SRC_VERT_BLOCK = R\"(\nuniform mat4 unWVP;\n\nin vec4 vPosition;\nin vec3 vColor;\nin vec3 vUV;\n\nout vec3 fUV;\nout vec3 fColor;\n\nvoid main() {\n    fUV = vUV;\n    fColor = vColor;\n    gl_Position = unWVP * vPosition;\n}\n)\";\nconst cString SRC_FRAG_BLOCK = R\"(\nin vec3 fUV;\nin vec3 fColor;\n\nout vec4 pColor;\n\nvoid main() {\n    vec3 ff = fract(fUV);\n    float f1 = min(ff.x, ff.y);\n    float f2 = max(ff.x, ff.y);\n    float f = 1.0 - max(1.0 - f1, f2);\n    pColor = vec4(fColor * f , 1);\n}\n)\";\n\n#ifdef _MSC_VER\n#pragma endregion\n#endif// _MSC_VER\n\nstruct VertexPosColor {\npublic:\n    f32v3 pos;\n    f32v2 uv;\n    color3 color;\n};\n\nf32v3 BLOCK_MODEL[24] = {\n    f32v3(0, 1, 0),\n    f32v3(0, 1, 1),\n    f32v3(0, 0, 0),\n    f32v3(0, 0, 1),\n\n    f32v3(1, 1, 1),\n    f32v3(1, 1, 0),\n    f32v3(1, 0, 1),\n    f32v3(1, 0, 0),\n\n    f32v3(0, 0, 1),\n    f32v3(1, 0, 1),\n    f32v3(0, 0, 0),\n    f32v3(1, 0, 0),\n\n    f32v3(0, 1, 0),\n    f32v3(1, 1, 0),\n    f32v3(0, 1, 1),\n    f32v3(1, 1, 1),\n\n    f32v3(1, 1, 0),\n    f32v3(0, 1, 0),\n    f32v3(1, 0, 0),\n    f32v3(0, 0, 0),\n\n    f32v3(0, 1, 1),\n    f32v3(1, 1, 1),\n    f32v3(0, 0, 1),\n    f32v3(1, 0, 1)\n};\nf32v2 BLOCK_UVS[4] = {\n    f32v2(0, 1),\n    f32v2(1, 1),\n    f32v2(0, 0),\n    f32v2(1, 0)\n};\n\nconst ui32 TEST_CHUNK_SIZE = 34;\n\nclass APICullSimple {\npublic:\n    APICullSimple(const ui16* data) :\n        m_data(data) {\n        // Empty\n    }\n\n    vvox::meshalg::VoxelFaces occludes(const ui16& v1, const ui16& v2, const vvox::Axis& axis VORB_MAYBE_UNUSED) const {\n        vvox::meshalg::VoxelFaces f = {};\n        if (v1 != 0 && v2 == 0) f.block1Face = true;\n        else if (v2 != 0 && v1 == 0) f.block2Face = true;\n        return f;\n    }\n    void result(const vvox::meshalg::VoxelQuad& quad) {\n        VertexPosColor v;\n        ColorRGBA8 c;\n        switch (m_data[quad.startIndex]) {\n        case 1:\n            c = ColorRGBA8((i32)(quad.voxelPosition.x / 3.0f * 255), (i32)(quad.voxelPosition.y / 3.0f * 255), (i32)(quad.voxelPosition.z / 3.0f * 255));\n            v.color = c.color.rgb;\n            break;\n        default:\n            v.color = color::Blue.color.rgb;\n            break;\n        }\n\n        f32v3 off(quad.voxelPosition);\n        f32v3 scale;\n\n        switch (quad.direction) {\n        case vvox::Cardinal::X_NEG:\n        case vvox::Cardinal::X_POS:\n            scale.x = 1;\n            scale.z = (f32)quad.size.x;\n            scale.y = (f32)quad.size.y;\n            break;\n        case vvox::Cardinal::Y_NEG:\n        case vvox::Cardinal::Y_POS:\n            scale.y = 1;\n            scale.x = (f32)quad.size.x;\n            scale.z = (f32)quad.size.y;\n            break;\n        case vvox::Cardinal::Z_NEG:\n        case vvox::Cardinal::Z_POS:\n            scale.z = 1;\n            scale.x = (f32)quad.size.x;\n            scale.y = (f32)quad.size.y;\n            break;\n        default:\n            break;\n        }\n\n        for (size_t i = 0; i < 4; i++) {\n            v.uv = BLOCK_UVS[i];\n            v.pos = off + BLOCK_MODEL[(size_t)quad.direction * 4 + i] * scale;\n            vertices.emplace_back(v);\n        }\n    }\n\n    std::vector<VertexPosColor> vertices;\nprivate:\n    const ui16* m_data;\n};\n\ni32 TestBlockView::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\ni32 TestBlockView::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestBlockView::build() {\n    // Empty\n}\nvoid TestBlockView::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestBlockView::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_hooks.addAutoHook(m_blocks.onBlockAddition, [&] (Sender s VORB_MAYBE_UNUSED, ui16 id) {\n        printf(\"Loaded Block: %s = %d\\n\", m_blocks[id].name.c_str(), id);\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::window.onFile, [&] (Sender s VORB_MAYBE_UNUSED, const vui::WindowFileEvent& e) {\n        loadBlocks(e.file);\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onMotion, [&] (Sender s VORB_MAYBE_UNUSED, const vui::MouseMotionEvent& e) {\n        if (m_movingCamera) {\n            m_mRotation = glm::rotate(f32m4(), 1.2f * e.dx, f32v3(0.0f, 1.0f, 0.0f)) * m_mRotation;\n            m_mRotation = glm::rotate(f32m4(), 1.2f * e.dy, f32v3(1.0f, 0.0f, 0.0f)) * m_mRotation;\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [&] (Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::MIDDLE) m_movingCamera = true;\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonUp, [&] (Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::MIDDLE) m_movingCamera = false;\n    });\n\n    m_program.init();\n    m_program.addShader(vg::ShaderType::VERTEX_SHADER, SRC_VERT_BLOCK);\n    m_program.addShader(vg::ShaderType::FRAGMENT_SHADER, SRC_FRAG_BLOCK);\n    m_program.link();\n    m_program.initAttributes();\n    m_program.initUniforms();\n    genBlockMesh();\n    m_mRotation = f32m4(1.0);\n    m_movingCamera = false;\n\n    // Set clear state\n    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);\n    glClearDepth(1.0);\n\n}\nvoid TestBlockView::onExit(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestBlockView::update(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\nvoid TestBlockView::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    m_program.use();\n    f32 tCenter = (f32)TEST_CHUNK_SIZE * -0.5f;\n    f32m4 mWVP = glm::perspectiveFov(90.0f, 800.0f, 600.0f, 0.1f, 1000.0f) * glm::lookAt(f32v3(0, 0, TEST_CHUNK_SIZE), f32v3(0, 0, 0), f32v3(0, 1, 0)) * m_mRotation * glm::translate(f32v3(tCenter, tCenter, tCenter));\n\n    vg::DepthState::FULL.set();\n    vg::RasterizerState::CULL_CLOCKWISE.set();\n\n    m_program.use();\n    m_program.enableVertexAttribArrays();\n\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, false, (f32*)&mWVP[0][0]);\n\n    glBindBuffer(GL_ARRAY_BUFFER, m_verts);\n    glVertexAttribPointer(m_program.getAttribute(\"vPosition\"), 3, GL_FLOAT, false, sizeof(VertexPosColor), offsetptr(VertexPosColor, pos));\n    glVertexAttribPointer(m_program.getAttribute(\"vUV\"), 2, GL_FLOAT, false, sizeof(VertexPosColor), offsetptr(VertexPosColor, uv));\n    glVertexAttribPointer(m_program.getAttribute(\"vColor\"), 3, GL_UNSIGNED_BYTE, true, sizeof(VertexPosColor), offsetptr(VertexPosColor, color));\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_inds);\n    glDrawElements(GL_TRIANGLES, m_indCount, GL_UNSIGNED_INT, nullptr);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    m_program.disableVertexAttribArrays();\n    vg::GLProgram::unuse();\n}\n\nvoid TestBlockView::loadBlocks(const cString file) {\n    vio::IOManager iom;\n    BlockLoader::load(iom, file, &m_blocks);\n}\n\nvoid TestBlockView::genBlockMesh() {\n    size_t vc = TEST_CHUNK_SIZE * TEST_CHUNK_SIZE * TEST_CHUNK_SIZE;\n    ui16* data = new ui16[vc]();\n    Random r;\n    r.seed(10);\n    for (ui32 z = 0; z < TEST_CHUNK_SIZE; z++) {\n        for (ui32 x = 0; x < TEST_CHUNK_SIZE; x++) {\n            ui32 h = (ui32)(r.genMH() * 4) + 15;\n            for (ui32 y = 0; y < h; y++) {\n                size_t vi = (y * TEST_CHUNK_SIZE + z) * TEST_CHUNK_SIZE + x;\n                \n                data[vi] = 1;\n            }\n        }\n    }\n\n    APICullSimple api(data);\n    api.vertices.reserve(10000);\n    vvox::meshalg::createCulled<ui16>(data, ui32v3(TEST_CHUNK_SIZE), &api);\n    delete[] data;\n\n    glGenBuffers(1, &m_verts);\n    glBindBuffer(GL_ARRAY_BUFFER, m_verts);\n    glBufferData(GL_ARRAY_BUFFER, api.vertices.size() * sizeof(VertexPosColor), api.vertices.data(), GL_STATIC_DRAW);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    m_indCount = (api.vertices.size()) / 4 * 6;\n    printf(\"Tris: %d\\n\", m_indCount / 3);\n\n    ui32* inds = vvox::meshalg::generateQuadIndices<ui32>(api.vertices.size() / 4);\n    glGenBuffers(1, &m_inds);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_inds);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indCount * sizeof(ui32), inds, GL_STATIC_DRAW);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    delete[] inds;\n}\n"
  },
  {
    "path": "SoA/TestBlockViewScreen.h",
    "content": "///\n/// TestBlockViewScreen.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 23 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Preview a block\n///\n\n#pragma once\n\n#ifndef TestBlockViewScreen_h__\n#define TestBlockViewScreen_h__\n\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/ui/IGameScreen.h>\n\n#include \"BlockPack.h\"\n\nclass TestBlockView : public vui::IGameScreen {\npublic:\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\nprivate:\n    /// Loads a file of block data\n    /// @param file: File containing block data\n    void loadBlocks(const cString file);\n\n    void genBlockMesh();\n\n    BlockPack m_blocks; ///< Block data\n    AutoDelegatePool m_hooks; ///< Input hooks reservoir\n    VGVertexBuffer m_verts;\n    VGVertexBuffer m_inds;\n    ui32 m_indCount;\n    vg::GLProgram m_program;\n    f32m4 m_mRotation;\n    bool m_movingCamera;\n};\n\n#endif // TestBlockViewScreen_h__"
  },
  {
    "path": "SoA/TestConnectedTextureScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestConnectedTextureScreen.h\"\n\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/colors.h>\n\n#include \"SoAState.h\"\n#include \"SoaEngine.h\"\n#include \"LoadTaskBlockData.h\"\n#include \"ChunkRenderer.h\"\n\n#include \"ChunkMeshTask.h\"\n\nTestConnectedTextureScreen::TestConnectedTextureScreen(const App* app, CommonState* state) :\nIAppScreen<App>(app),\nm_commonState(state),\nm_soaState(m_commonState->state) {\n\n}\n\ni32 TestConnectedTextureScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestConnectedTextureScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestConnectedTextureScreen::build() {\n\n}\n\nvoid TestConnectedTextureScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n\n}\n\nvoid TestConnectedTextureScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        if(e.keyCode==VKEY_ESCAPE)\n        {\n            exit(0);\n        }\n    });\n\n    // Init spritebatch and font\n    m_sb.init();\n    m_font.init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n    // Init game state\n    SoaEngine::initState(m_commonState->state);\n\n    // Init renderer\n    m_renderer.init();\n\n    { // Init post processing\n        Array<vg::GBufferAttachment> attachments;\n        vg::GBufferAttachment att[2];\n        // Color\n        att[0].format = vg::TextureInternalFormat::RGBA16F;\n        att[0].pixelFormat = vg::TextureFormat::RGBA;\n        att[0].pixelType = vg::TexturePixelType::UNSIGNED_BYTE;\n        att[0].number = 1;\n        // Normals\n        att[1].format = vg::TextureInternalFormat::RGBA16F;\n        att[1].pixelFormat = vg::TextureFormat::RGBA;\n        att[1].pixelType = vg::TexturePixelType::UNSIGNED_BYTE;\n        att[1].number = 2;\n        m_hdrTarget.setSize(m_commonState->window->getWidth(), m_commonState->window->getHeight());\n        m_hdrTarget.init(Array<vg::GBufferAttachment>(att, 2), vg::TextureInternalFormat::RGBA8).initDepth();\n    \n        // Swapchain\n        m_swapChain.init(m_commonState->window->getWidth(), m_commonState->window->getHeight(), vg::TextureInternalFormat::RGBA16F);\n   \n        // Init the FullQuadVBO\n        m_commonState->quad.init();\n\n        // SSAO\n        m_ssaoStage.init(m_commonState->window, m_commonState->loadContext);\n        m_ssaoStage.load(m_commonState->loadContext);\n        m_ssaoStage.hook(&m_commonState->quad, m_commonState->window->getWidth(), m_commonState->window->getHeight());\n\n        // HDR\n        m_hdrStage.init(m_commonState->window, m_commonState->loadContext);\n        m_hdrStage.load(m_commonState->loadContext);\n        m_hdrStage.hook(&m_commonState->quad);\n    }\n\n    // Load blocks\n    LoadTaskBlockData blockLoader(&m_soaState->blocks,\n                                  &m_soaState->clientState.blockTextureLoader,\n                                  &m_commonState->loadContext);\n    blockLoader.load();\n\n    // Uploads all the needed textures\n    m_soaState->clientState.blockTextures->update();\n\n    initChunks();\n\n    // Create all chunk meshes\n    m_mesher.init(&m_soaState->blocks);\n    for (auto& cv : m_chunks) {\n        cv.chunkMesh = m_mesher.easyCreateChunkMesh(cv.chunk, MeshTaskType::DEFAULT);\n    }\n\n    { // Init the camera\n        m_camera.init(m_commonState->window->getAspectRatio());\n        m_camera.setPosition(f64v3(16.0, 17.0, 33.0));\n        m_camera.setDirection(f32v3(0.0f, 0.0f, -1.0f));\n        m_camera.setRight(f32v3(1.0f, 0.0f, 0.0f));\n        m_camera.setUp(f32v3(0.0f, 1.0f, 0.0f));\n    }\n\n    initInput();\n\n    // Set GL state\n    glEnable(GL_DEPTH_TEST);\n    glEnable(GL_CULL_FACE);\n    glClearDepth(1.0);\n}\n\nvoid TestConnectedTextureScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    for (auto& cv : m_chunks) {\n        m_mesher.freeChunkMesh(cv.chunkMesh);\n    }\n    m_hdrTarget.dispose();\n    m_swapChain.dispose();\n}\n\nvoid TestConnectedTextureScreen::update(const vui::GameTime& gameTime) {\n    f32 speed = 5.0f;\n    if (m_movingFast) speed *= 5.0f;\n    if (m_movingForward) {\n        f32v3 offset = m_camera.getDirection() * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingBack) {\n        f32v3 offset = m_camera.getDirection() * -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingLeft) {\n        f32v3 offset = m_camera.getRight() * -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingRight) {\n        f32v3 offset = m_camera.getRight() * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingUp) {\n        f32v3 offset = f32v3(0, 1, 0) * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if (m_movingDown) {\n        f32v3 offset = f32v3(0, 1, 0) *  -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    m_camera.update();\n}\n\nvoid TestConnectedTextureScreen::draw(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Bind the FBO\n    m_hdrTarget.useGeometry();\n\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n    if (m_wireFrame) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n\n    m_renderer.beginOpaque(m_soaState->clientState.blockTextures->getAtlasTexture(),\n                           f32v3(0.0f, 0.0f, -1.0f), f32v3(1.0f),\n                           f32v3(0.3f));\n    m_renderer.drawOpaque(m_chunks[m_activeChunk].chunkMesh, m_camera.getPosition(), m_camera.getViewProjectionMatrix());\n    m_renderer.end();\n\n    if (m_wireFrame) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\n    // Post processing\n    m_swapChain.reset(0, m_hdrTarget.getGeometryID(), m_hdrTarget.getGeometryTexture(0), soaOptions.get(OPT_MSAA).value.i > 0, false);\n\n    // Render SSAO\n    m_ssaoStage.set(m_hdrTarget.getDepthTexture(), m_hdrTarget.getGeometryTexture(1), m_hdrTarget.getGeometryTexture(0), m_swapChain.getCurrent().getID());\n    m_ssaoStage.render(&m_camera);\n    m_swapChain.swap();\n    m_swapChain.use(0, false);\n\n    // Draw to backbuffer for the last effect\n    // TODO(Ben): Do we really need to clear depth here...\n    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n    glDrawBuffer(GL_BACK);\n    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, m_hdrTarget.getDepthTexture());\n    m_hdrStage.render();\n\n    // Draw UI\n    m_sb.begin();\n    m_sb.drawString(&m_font, (std::to_string(m_activeChunk) + \". \" + m_chunks[m_activeChunk].name).c_str(), f32v2(30.0f), f32v2(1.0f), color::White);\n    m_sb.end();\n    m_sb.render(f32v2(m_commonState->window->getViewportDims()));\n    vg::DepthState::FULL.set(); // Have to restore depth\n}\n\nvoid TestConnectedTextureScreen::initChunks() {\n    ui16 grass = m_soaState->blocks.getBlockIndex(\"grass\");\n    ui16 dirt = m_soaState->blocks.getBlockIndex(\"dirt\");\n    // TODO(Ben): Allow users to pick block\n    { // Grass 1\n        Chunk* chunk = addChunk(\"Grass 1\");\n        chunk->setBlock(15, 16, 16, grass);\n        chunk->setBlock(16, 16, 16, grass);\n        chunk->setBlock(17, 16, 16, grass);\n        chunk->setBlock(15, 15, 17, grass);\n        chunk->setBlock(16, 15, 17, grass);\n        chunk->setBlock(17, 15, 17, grass);\n        chunk->setBlock(15, 15, 18, grass);\n        chunk->setBlock(16, 14, 18, grass);\n        chunk->setBlock(17, 14, 18, grass);\n        chunk->setBlock(15, 13, 19, grass);\n        chunk->setBlock(16, 13, 19, grass);\n        chunk->setBlock(17, 14, 19, grass);\n    }\n    { // Hourglass\n        Chunk* chunk = addChunk(\"Hourglass\");\n        for (int y = 0; y < HALF_CHUNK_WIDTH; y++) {\n            for (int z = y; z < CHUNK_WIDTH - y; z++) {\n                for (int x = y; x < CHUNK_WIDTH - y; x++) {\n                    chunk->setBlock(x, y, z, grass);\n                    chunk->setBlock(x, CHUNK_WIDTH - y - 1, z, grass);\n                }\n            }\n        }\n        for (int y = 0; y < CHUNK_WIDTH; y++) {\n            chunk->setBlock(0, y, 0, dirt);\n            chunk->setBlock(CHUNK_WIDTH_M1, y, CHUNK_WIDTH_M1, dirt);\n        }\n\n    }\n    { // Flat\n        Chunk* chunk = addChunk(\"Flat\");\n        for (int i = 0; i < CHUNK_LAYER; i++) {\n            chunk->blocks.set(CHUNK_LAYER * 15 + i, grass);\n        }\n    }\n}\n\nvoid TestConnectedTextureScreen::initInput() {\n    m_mouseButtons[0] = false;\n    m_mouseButtons[1] = false;\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onMotion, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseMotionEvent& e) {\n        if (m_mouseButtons[0]) {\n            m_camera.rotateFromMouse((f32)-e.dx, (f32)-e.dy, 0.1f);\n        }\n        if (m_mouseButtons[1]) {\n            m_camera.rollFromMouse((f32)e.dx, 0.1f);\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::LEFT) m_mouseButtons[0] = true;\n        if (e.button == vui::MouseButton::RIGHT) m_mouseButtons[1] = true;\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::LEFT) m_mouseButtons[0] = false;\n        if (e.button == vui::MouseButton::RIGHT) m_mouseButtons[1] = false;\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        switch (e.keyCode) {\n            case VKEY_W:\n                m_movingForward = true;\n                break;\n            case VKEY_S:\n                m_movingBack = true;\n                break;\n            case VKEY_A:\n                m_movingLeft = true;\n                break;\n            case VKEY_D:\n                m_movingRight = true;\n                break;\n            case VKEY_SPACE:\n                m_movingUp = true;\n                break;\n            case VKEY_LSHIFT:\n                m_movingFast = true;\n                break;\n            case VKEY_M:\n                m_wireFrame = !m_wireFrame;\n                break;\n            case VKEY_LEFT:\n                if (m_activeChunk == 0) {\n                    m_activeChunk = m_chunks.size() - 1;\n                } else {\n                    m_activeChunk--;\n                }\n                break;\n            case VKEY_RIGHT:\n                m_activeChunk++;\n                if (m_activeChunk >= (int)m_chunks.size()) m_activeChunk = 0;\n                break;\n            case VKEY_F10:\n                // Reload meshes\n                // TODO(Ben): Destroy meshes\n                for (auto& cv : m_chunks) {\n                    m_mesher.freeChunkMesh(cv.chunkMesh);\n                    cv.chunkMesh = m_mesher.easyCreateChunkMesh(cv.chunk, MeshTaskType::DEFAULT);\n                }\n                break;\n            case VKEY_F11:\n                // Reload shaders\n                m_renderer.dispose();\n                m_renderer.init();\n                m_ssaoStage.reloadShaders();\n                break;\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        switch (e.keyCode) {\n            case VKEY_W:\n                m_movingForward = false;\n                break;\n            case VKEY_S:\n                m_movingBack = false;\n                break;\n            case VKEY_A:\n                m_movingLeft = false;\n                break;\n            case VKEY_D:\n                m_movingRight = false;\n                break;\n            case VKEY_SPACE:\n                m_movingUp = false;\n                break;\n            case VKEY_LSHIFT:\n                m_movingFast = false;\n                break;\n        }\n    });\n}\n\nChunk* TestConnectedTextureScreen::addChunk(const nString& name) {\n    Chunk* chunk = new Chunk;\n    // TODO(Ben): This is wrong now, need accessor\n    chunk->initAndFillEmpty(WorldCubeFace::FACE_TOP);\n    // TODO(Ben): AOS\n    ViewableChunk viewable;\n    viewable.chunk = chunk;\n    viewable.name = name;\n    m_chunks.push_back(viewable);\n    return chunk;\n}"
  },
  {
    "path": "SoA/TestConnectedTextureScreen.h",
    "content": "///\n/// TestConnectedTextureScreen.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 2 Jul 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Test screen to help artists with connected textures\n///\n\n#pragma once\n\n#ifndef TestConnectedTextureScreen_h__\n#define TestConnectedTextureScreen_h__\n\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/GBuffer.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/RTSwapChain.hpp>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/ui/IGameScreen.h>\n\n#include \"BlockPack.h\"\n#include \"Camera.h\"\n#include \"Chunk.h\"\n#include \"CommonState.h\"\n#include \"ChunkMesher.h\"\n#include \"ChunkRenderer.h\"\n#include \"SsaoRenderStage.h\"\n#include \"HdrRenderStage.h\"\n\nclass TestConnectedTextureScreen : public vui::IAppScreen<App> {\npublic:\n    TestConnectedTextureScreen(const App* app, CommonState* state);\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    i32 getNextScreen() const override;\n    i32 getPreviousScreen() const override;\n    void build() override;\n    void destroy(const vui::GameTime& gameTime) override;\n    void onEntry(const vui::GameTime& gameTime) override;\n    void onExit(const vui::GameTime& gameTime) override;\n    void update(const vui::GameTime& gameTime) override;\n    void draw(const vui::GameTime& gameTime) override;\nprivate:\n    void initChunks();\n    void initInput();\n    Chunk* addChunk(const nString& name);\n\n    struct ViewableChunk {\n        Chunk* chunk;\n        ChunkMesh* chunkMesh;\n        nString name;\n    };\n\n    AutoDelegatePool m_hooks; ///< Input hooks reservoir\n    Camera m_camera;\n    BlockPack m_blocks; ///< Block data\n    CommonState* m_commonState;\n    SoaState* m_soaState;\n    ChunkRenderer m_renderer;\n    ChunkMesher m_mesher;\n\n    vg::SpriteBatch m_sb;\n    vg::SpriteFont m_font;\n\n    std::vector <ViewableChunk> m_chunks;\n\n    vg::GBuffer m_hdrTarget; ///< Framebuffer needed for the HDR rendering\n    vg::RTSwapChain<2> m_swapChain; ///< Swap chain of framebuffers used for post-processing\n\n    SSAORenderStage m_ssaoStage;\n    HdrRenderStage m_hdrStage;\n\n    bool m_wireFrame = false;\n    bool m_mouseButtons[2];\n    bool m_movingForward = false;\n    bool m_movingBack = false;\n    bool m_movingLeft = false;\n    bool m_movingRight = false;\n    bool m_movingUp = false;\n    bool m_movingDown = false;\n    bool m_movingFast = false;\n\n    int m_activeChunk = 0;\n};\n\n#endif // TestConnectedTextureScreen_h__"
  },
  {
    "path": "SoA/TestConsoleScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestConsoleScreen.h\"\n\n#include <Vorb/ui/InputDispatcher.h>\n\ni32 TestConsoleScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\ni32 TestConsoleScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestConsoleScreen::build() {\n    // Empty\n}\nvoid TestConsoleScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestConsoleScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n// #ifdef VORB_LUA\n//     m_delegatePool.addAutoHook(m_console.onStream[DEV_CONSOLE_STREAM_OUT], [&] (Sender sender VORB_MAYBE_UNUSED, const cString s) {\n//         printf(\"Out:   %s\\n\", s);\n//     });\n//     m_delegatePool.addAutoHook(m_console.onStream[DEV_CONSOLE_STREAM_ERR], [&] (Sender sender VORB_MAYBE_UNUSED, const cString s) {\n//         printf(\"Err:   %s\\n\", s);\n//     });\n//     m_delegatePool.addAutoHook(m_text.onTextChange, [&] (Sender sender VORB_MAYBE_UNUSED, const cString s) {\n//         printf(\"\\rInput: %s  \", s);\n//     });\n//     m_delegatePool.addAutoHook(m_text.onTextEntry, [&] (Sender sender VORB_MAYBE_UNUSED, const cString s) {\n//         printf(\"\\rComm:  %s\\n\", s);\n//         m_console.invokeCommand(s);\n//     });\n//     m_text.start();\n//     printf(\"Welcome to Lua REPL\\nInput: \");\n// #endif//VORB_LUA\n    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);\n    glClearDepth(1.0);\n}\nvoid TestConsoleScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_text.stop();\n    m_delegatePool.dispose();\n}\n\nvoid TestConsoleScreen::update(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\nvoid TestConsoleScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n}\n"
  },
  {
    "path": "SoA/TestConsoleScreen.h",
    "content": "///\n/// TestConsoleScreen.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 14 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Tests out the Lua dev console\n///\n\n#pragma once\n\n#ifndef TestConsoleScreen_h__\n#define TestConsoleScreen_h__\n\n#include <Vorb/Event.hpp>\n#include <Vorb/ui/IGameScreen.h>\n// #include <Vorb/ui/LuaDevConsole.h>\n#include <Vorb/ui/TextInputListener.hpp>\n\n// TODO(Matthew): Implement.\nclass TestConsoleScreen : public vui::IGameScreen {\npublic:\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\nprivate:\n// #ifdef VORB_LUA\n//     vui::LuaDevConsole m_console; ///< Console used for testing\n// #endif//VORB_LUA\n\n    vui::TextInputListener<char> m_text; ///< Text input\n    AutoDelegatePool m_delegatePool; ///< Input hooks reservoir\n};\n\n#endif // TestConsoleScreen_h__"
  },
  {
    "path": "SoA/TestDeferredScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestDeferredScreen.h\"\n\n#include \"ShaderLoader.h\"\n#include <Vorb/colors.h>\n#include <Vorb/graphics/GLStates.h>\n#include <Vorb/graphics/GLRenderTarget.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/io/IOManager.h>\n\n#include <glm/gtx/transform.hpp>\n#include <glm/gtc/matrix_transform.hpp>\n\n// Number cells per row/column in a single grid\nconst ui32 CELLS = 20;\n\nvg::DepthState dsLightPoint(true, vg::DepthFunction::GREATER, false);\nvg::DepthState dsLightDirectional(true, vg::DepthFunction::NOTEQUAL, false);\n\nstruct DefVertex {\npublic:\n    f32v3 position;\n    f32v3 normal;\n};\n\nTestDeferredScreen::TestDeferredScreen() :\nm_sb(true, false) {\n    // Empty\n}\n\ni32 TestDeferredScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\ni32 TestDeferredScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestDeferredScreen::build() {\n    // Empty\n}\nvoid TestDeferredScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestDeferredScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_eyePos = f32v3(0, 0, 4);\n    buildGeometry();\n    buildLightMaps();\n\n    m_gbuffer = vg::GBuffer(m_game->getWindow().getWidth(), m_game->getWindow().getHeight());\n    Array<vg::GBufferAttachment> ga;\n    ga.setData(4);\n    ga[0].format = vg::TextureInternalFormat::RGBA16F;\n    ga[0].pixelFormat = vg::TextureFormat::RGBA;\n    ga[0].pixelType = vg::TexturePixelType::HALF_FLOAT;\n    ga[0].number = 0;\n    ga[1] = ga[0];\n    ga[1].number = 1;\n    ga[2].format = vg::TextureInternalFormat::RG32F;\n    ga[2].pixelFormat = vg::TextureFormat::RG;\n    ga[2].pixelType = vg::TexturePixelType::FLOAT;\n    ga[2].number = 2;\n    m_gbuffer.init(ga, vg::TextureInternalFormat::RGB16F).initDepthStencil();\n\n    m_sb.init();\n\n    { // Init Shaders\n        m_deferredPrograms.clear = ShaderLoader::createProgramFromFile(\"Shaders/Deferred/Clear.vert\",\n                                                                       \"Shaders/Deferred/Clear.frag\");\n\n        m_deferredPrograms.composition = ShaderLoader::createProgramFromFile(\"Shaders/Deferred/Composition.vert\",\n                                                                             \"Shaders/Deferred/Composition.frag\");\n\n        m_deferredPrograms.geometry[\"Basic\"] = ShaderLoader::createProgramFromFile(\"Shaders/Deferred/Geometry.vert\",\n                                                                                   \"Shaders/Deferred/Geometry.frag\");\n\n        m_deferredPrograms.light[\"Directional\"] = ShaderLoader::createProgramFromFile(\"Shaders/Deferred/LightDirectional.vert\",\n                                                                                      \"Shaders/Deferred/LightDirectional.frag\");\n    }\n\n    m_quad.init(0);\n\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&] (Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        switch (e.keyCode) {\n        case VKEY_I: if(m_roughness < 0.96) m_roughness += 0.05f; break;\n        case VKEY_J: if (m_roughness > 0.04) m_roughness -= 0.05f; break;\n        case VKEY_O: if (m_reflectance < 0.91) m_reflectance += 0.1f; break;\n        case VKEY_K: if (m_reflectance > 0.09) m_reflectance -= 0.1f; break;\n        case VKEY_P: if (m_metalness < 0.5) m_metalness = 1; break;\n        case VKEY_L: if (m_metalness > 0.5) m_metalness = 0; break;\n        default:\n            break;\n        }\n    });\n    m_reflectance = 0.0f;\n    m_roughness = 1.0f;\n    m_metalness = 1.0f;\n\n    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);\n    glClearDepth(1.0);\n}\nvoid TestDeferredScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    glDeleteBuffers(1, &m_verts);\n    glDeleteBuffers(1, &m_inds);\n    m_deferredPrograms.dispose();\n    m_sb.dispose();\n    m_quad.dispose();\n    m_gbuffer.dispose();\n}\n\nvoid TestDeferredScreen::update(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n    f32v4 rotated = f32v4(m_eyePos, 1) * glm::rotate(f32m4(), (float)(10 * gameTime.elapsed), f32v3(0, 1, 0));\n    m_eyePos.x = rotated.x;\n    m_eyePos.y = rotated.y;\n    m_eyePos.z = rotated.z;\n}\n\nvoid TestDeferredScreen::draw(const vui::GameTime& gameTime VORB_UNUSED) {\n    /************************************************************************/\n    /* Deferred pass                                                        */\n    /************************************************************************/\n    m_gbuffer.useGeometry();\n\n    // Clear the GBuffer\n    glBlendFunc(GL_ONE, GL_ZERO);\n    vg::DepthState::WRITE.set();\n    m_deferredPrograms.clear.use();\n    m_quad.draw();\n    \n    f32m4 mVP = glm::perspectiveFov(90.0f, 800.0f, 600.0f, 0.1f, 1000.0f) * glm::lookAt(m_eyePos, f32v3(0, 0, 0), f32v3(0, 1, 0));\n    f32m4 mVPInv = glm::inverse(mVP);\n\n    vg::DepthState::FULL.set();\n    vg::RasterizerState::CULL_CLOCKWISE.set();\n\n    vg::GLProgram& progGeo = m_deferredPrograms.geometry[\"Basic\"];\n    progGeo.use();\n    progGeo.enableVertexAttribArrays();\n\n    glUniformMatrix4fv(progGeo.getUniform(\"unVP\"), 1, false, (f32*)&mVP[0][0]);\n\n    glBindBuffer(GL_ARRAY_BUFFER, m_verts);\n    glVertexAttribPointer(progGeo.getAttribute(\"vPosition\"), 3, GL_FLOAT, false, sizeof(DefVertex), offsetptr(DefVertex, position));\n    glVertexAttribPointer(progGeo.getAttribute(\"vNormal\"), 3, GL_FLOAT, false, sizeof(DefVertex), offsetptr(DefVertex, normal));\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_inds);\n\n    f32m4 mW = glm::translate(f32m4(1.0f), f32v3(-1.3f, -1, 0));\n    f32m3 mWIT = f32m3(glm::transpose(glm::inverse(mW)));\n    glUniformMatrix4fv(progGeo.getUniform(\"unWorld\"), 1, false, (f32*)&mW[0][0]);\n    glUniformMatrix3fv(progGeo.getUniform(\"unWorldIT\"), 1, false, (f32*)&mWIT[0][0]);\n    glDrawElements(GL_TRIANGLES, m_indexCount, GL_UNSIGNED_INT, nullptr);\n\n    mW = glm::translate(f32m4(1.0f), f32v3(1.3f, 1, 0));\n    mWIT = f32m3(glm::transpose(glm::inverse(mW)));\n    glUniformMatrix4fv(progGeo.getUniform(\"unWorld\"), 1, false, (f32*)&mW[0][0]);\n    glUniformMatrix3fv(progGeo.getUniform(\"unWorldIT\"), 1, false, (f32*)&mWIT[0][0]);\n    glDrawElements(GL_TRIANGLES, m_indexCount, GL_UNSIGNED_INT, nullptr);\n\n    mW = glm::translate(f32m4(1.0f), f32v3(0, 0, -2));\n    mWIT = f32m3(glm::transpose(glm::inverse(mW)));\n    glUniformMatrix4fv(progGeo.getUniform(\"unWorld\"), 1, false, (f32*)&mW[0][0]);\n    glUniformMatrix3fv(progGeo.getUniform(\"unWorldIT\"), 1, false, (f32*)&mWIT[0][0]);\n    glDrawElements(GL_TRIANGLES, m_indexCount, GL_UNSIGNED_INT, nullptr);\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    progGeo.disableVertexAttribArrays();\n\n    /************************************************************************/\n    /* Lighting pass                                                        */\n    /************************************************************************/\n    m_gbuffer.useLight();\n    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);\n    glClear(GL_COLOR_BUFFER_BIT);\n    glBlendFunc(GL_ONE, GL_ONE);\n\n    {\n        dsLightDirectional.set();\n\n        vg::GLProgram& progLight = m_deferredPrograms.light[\"Directional\"];\n        progLight.use();\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, m_gbuffer.getGeometryTexture(1));\n        glUniform1i(progLight.getUniform(\"unTexNormal\"), 0);\n        glActiveTexture(GL_TEXTURE1);\n        glBindTexture(GL_TEXTURE_2D, m_gbuffer.getGeometryTexture(2));\n        glUniform1i(progLight.getUniform(\"unTexDepth\"), 1);\n        glActiveTexture(GL_TEXTURE2);\n        glBindTexture(GL_TEXTURE_CUBE_MAP, m_envMap);\n        glUniform1i(progLight.getUniform(\"unTexEnvironment\"), 2);\n        glUniformMatrix4fv(progLight.getUniform(\"unVPInv\"), 1, false, (f32*)&mVPInv[0][0]);\n        glUniform3f(progLight.getUniform(\"unEyePosition\"), m_eyePos.x, m_eyePos.y, m_eyePos.z);\n        glUniform1f(progLight.getUniform(\"unRoughness\"), m_roughness);\n        glUniform1f(progLight.getUniform(\"unReflectance\"), m_reflectance * 0.96f + 0.04f);\n        glUniform1f(progLight.getUniform(\"unMetalness\"), m_metalness);\n\n        //const size_t NUM_LIGHTS = 3;\n        //f32v3 lightDirs[NUM_LIGHTS] = {\n        //    f32v3(0, 0, -1),\n        //    f32v3(2, -1, 0),\n        //    f32v3(-1, 1, -1)\n        //    //f32v3(-4, -3, 0),\n        //    //f32v3(6, 3, 2)\n        //};\n        //f32v3 lightColors[NUM_LIGHTS] = {\n        //    f32v3(0.6, 0.6, 0.3),\n        //    f32v3(1.0, 0.0, 0.0),\n        //    f32v3(0.0, 1.0, 0.0)\n        //    //f32v3(0.0, 1.0, 1.0),\n        //    //f32v3(1.0, 0.0, 1.0)\n        //};\n        //for (size_t i = 0; i < NUM_LIGHTS; i++) {\n        //    f32v3 lightDir = glm::normalize(lightDirs[i]);\n        //    glUniform3f(progLight.getUniform(\"unLightDirection\"), lightDir.x, lightDir.y, lightDir.z);\n        //    f32v3 lightColor = lightColors[i];\n        //    glUniform3f(progLight.getUniform(\"unLightIntensity\"), lightColor.x, lightColor.y, lightColor.z);\n        //}\n        m_quad.draw();\n    }\n    {\n        dsLightPoint.set();\n\n        /*vg::GLProgram& progLight = m_deferredPrograms.light[\"Point\"];\n        progLight.use();\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, m_gbuffer.getGeometryTexture(1));\n        glUniform1i(progLight.getUniform(\"unTexNormal\"), 0);\n\n        const size_t NUM_LIGHTS = 5;\n        f32v3 lightDirs[NUM_LIGHTS] = {\n            f32v3(0, -2, -1),\n            f32v3(2, -1, 0),\n            f32v3(-1, 1, -1),\n            f32v3(-4, -3, 0),\n            f32v3(6, 3, 2)\n        };\n        f32v3 lightColors[NUM_LIGHTS] = {\n            f32v3(0.6, 0.6, 0.3),\n            f32v3(1.0, 0.0, 0.0),\n            f32v3(0.0, 1.0, 0.0),\n            f32v3(0.0, 1.0, 1.0),\n            f32v3(1.0, 0.0, 1.0)\n        };\n        for (size_t i = 0; i < NUM_LIGHTS; i++) {\n            f32v3 lightDir = glm::normalize(lightDirs[i]);\n            glUniform3f(progLight.getUniform(\"unLightDirection\"), lightDir.x, lightDir.y, lightDir.z);\n            f32v3 lightColor = lightColors[i];\n            glUniform3f(progLight.getUniform(\"unLightColor\"), lightColor.x, lightColor.y, lightColor.z);\n            m_quad.draw();\n        }*/\n    }\n\n    /************************************************************************/\n    /* Compose deferred and lighting                                        */\n    /************************************************************************/\n    vg::GLRenderTarget::unuse(m_game->getWindow().getWidth(), m_game->getWindow().getHeight());\n    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);\n    glClearDepth(1.0);\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    glBlendFunc(GL_ONE, GL_ZERO);\n    vg::DepthState::WRITE.set();\n    m_deferredPrograms.composition.use();\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D, m_gbuffer.getGeometryTexture(0));\n    glUniform1i(m_deferredPrograms.composition.getUniform(\"unTexColor\"), 0);\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, m_gbuffer.getGeometryTexture(2));\n    glUniform1i(m_deferredPrograms.composition.getUniform(\"unTexDepth\"), 1);\n    glActiveTexture(GL_TEXTURE2);\n    glBindTexture(GL_TEXTURE_2D, m_gbuffer.getLightTexture());\n    glUniform1i(m_deferredPrograms.composition.getUniform(\"unTexLight\"), 2);\n    m_quad.draw();\n\n    /************************************************************************/\n    /* Debug                                                                */\n    /************************************************************************/\n    m_sb.begin();\n    m_sb.draw(m_gbuffer.getGeometryTexture(0), f32v2(0, 0), f32v2(200, 150), color::White);\n    m_sb.draw(m_gbuffer.getGeometryTexture(1), f32v2(200, 0), f32v2(200, 150), color::White);\n    m_sb.draw(m_gbuffer.getGeometryTexture(2), f32v2(400, 0), f32v2(200, 150), color::White);\n    m_sb.draw(m_gbuffer.getLightTexture(), f32v2(600, 0), f32v2(200, 150), color::White);\n    m_sb.end();\n    m_sb.render(f32v2(m_game->getWindow().getWidth(), m_game->getWindow().getHeight()));\n}\n\nvoid TestDeferredScreen::buildGeometry() {\n    // Make vertices\n    ui32 cellPoints = CELLS + 1;\n    ui32 gridPoints = cellPoints * cellPoints;\n    DefVertex* verts = new DefVertex[gridPoints * 2];\n    size_t i = 0;\n    for (size_t y = 0; y < cellPoints; y++) {\n        for (size_t x = 0; x < cellPoints; x++) {\n            f32v3 pos((f32)x / (f32)CELLS, 0, (f32)y / (f32)CELLS);\n            pos.x -= 0.5f;\n            pos.x *= 2.0f;\n            pos.z -= 0.5f;\n            pos.z *= 2.0f;\n            pos.x = glm::sign(pos.x) * (sin(abs(pos.x) * 1.57079f));\n            pos.z = glm::sign(pos.z) * (sin(abs(pos.z) * 1.57079f));\n\n            f32 lp = glm::length(pos);\n            if (lp < 0.00001) {\n                pos.y = 1.0f;\n            } else {\n                f32 d = std::max(abs(pos.x), abs(pos.z));\n                pos /= lp;\n                pos *= d;\n                pos.y = sin(acos(d));\n            }\n\n            verts[i].position = pos;\n            verts[i].normal = glm::normalize(verts[i].position);\n            pos.y = -pos.y;\n            verts[gridPoints + i].position = pos;\n            verts[gridPoints + i].normal = glm::normalize(verts[gridPoints + i].position);\n            i++;\n        }\n    }\n\n    // Make indices\n    ui32 gridInds = 6 * CELLS * CELLS;\n    m_indexCount = gridInds * 2;\n    ui32* inds = new ui32[m_indexCount];\n    i = 0;\n    for (size_t y = 0; y < CELLS; y++) {\n        for (size_t x = 0; x < CELLS; x++) {\n            ui32 vi = y * cellPoints + x;\n            inds[i] = vi;\n            inds[i + 1] = vi + cellPoints;\n            inds[i + 2] = vi + 1;\n            inds[i + 3] = vi + 1;\n            inds[i + 4] = vi + cellPoints;\n            inds[i + 5] = vi + cellPoints + 1;\n\n            vi += gridPoints;\n            inds[gridInds + i] = vi;\n            inds[gridInds + i + 1] = vi + 1;\n            inds[gridInds + i + 2] = vi + cellPoints;\n            inds[gridInds + i + 3] = vi + cellPoints;\n            inds[gridInds + i + 4] = vi + 1;\n            inds[gridInds + i + 5] = vi + cellPoints + 1;\n\n            i += 6;\n        }\n    }\n\n    // Fill buffers\n    glGenBuffers(1, &m_verts);\n    glBindBuffer(GL_ARRAY_BUFFER, m_verts);\n    glBufferData(GL_ARRAY_BUFFER, gridPoints * 2 * sizeof(DefVertex), verts, GL_STATIC_DRAW);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    delete[] verts;\n    glGenBuffers(1, &m_inds);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_inds);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(ui32), inds, GL_STATIC_DRAW);\n    delete[] inds;\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n}\nvoid TestDeferredScreen::buildLightMaps() {\n    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);\n    glGenTextures(1, &m_envMap);\n    glBindTexture(GL_TEXTURE_CUBE_MAP, m_envMap);\n    \n    vg::ImageIO imageLoader;\n    vg::ScopedBitmapResource rs0(imageLoader.load(\"Textures/Test/nx.png\"));\n    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB16F, rs0.width, rs0.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rs0.data);\n    vg::ScopedBitmapResource rs1(imageLoader.load(\"Textures/Test/px.png\"));\n    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB16F, rs1.width, rs1.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rs1.data);\n    vg::ScopedBitmapResource rs2(imageLoader.load(\"Textures/Test/ny.png\"));\n    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB16F, rs2.width, rs2.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rs2.data);\n    vg::ScopedBitmapResource rs3(imageLoader.load(\"Textures/Test/py.png\"));\n    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB16F, rs3.width, rs3.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rs3.data);\n    vg::ScopedBitmapResource rs4(imageLoader.load(\"Textures/Test/nz.png\"));\n    glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB16F, rs4.width, rs4.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rs4.data);\n    vg::ScopedBitmapResource rs5(imageLoader.load(\"Textures/Test/pz.png\"));\n    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB16F, rs5.width, rs5.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rs5.data);\n\n    vg::SamplerState ss(\n        (VGEnum)vg::TextureMinFilter::LINEAR_MIPMAP_LINEAR,\n        (VGEnum)vg::TextureMagFilter::LINEAR,\n        (VGEnum)vg::TextureWrapMode::REPEAT,\n        (VGEnum)vg::TextureWrapMode::REPEAT,\n        (VGEnum)vg::TextureWrapMode::REPEAT\n        );\n    ss.set(GL_TEXTURE_CUBE_MAP);\n    glGenerateMipmap(GL_TEXTURE_CUBE_MAP);\n}"
  },
  {
    "path": "SoA/TestDeferredScreen.h",
    "content": "///\n/// TestDeferredScreen.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 16 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Development test for deferred rendering\n///\n\n#pragma once\n\n#ifndef TestDeferredScreen_h__\n#define TestDeferredScreen_h__\n\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/DeferredShaders.h>\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GBuffer.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/gtypes.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/ui/IGameScreen.h>\n\nclass TestDeferredScreen : public vui::IGameScreen {\npublic:\n    /// \n    TestDeferredScreen();\n\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\nprivate:\n    void buildGeometry();\n    void buildLightMaps();\n\n    f32v3 m_eyePos;\n\n    VGVertexBuffer m_verts; ///< Sphere's vertex buffer (of positions)\n    VGIndexBuffer m_inds; ///< Sphere's index buffer\n    ui32 m_indexCount; ///< Number of indices for sphere\n    vg::DeferredShaders m_deferredPrograms; ///< Basic rendering programs\n    vg::FullQuadVBO m_quad; ///< Used for GBuffer clearing operations\n    vg::GBuffer m_gbuffer; ///< Geometry buffer of deferred rendering\n    vg::SpriteBatch m_sb; ///< Debug SpriteBatch\n    AutoDelegatePool m_hooks; ///< Input hooks reservoir\n    VGTexture m_envMap; ///< Environment map\n    f32 m_roughness, m_reflectance, m_metalness; ///< Temp test values\n};\n\n#endif // TestDeferredScreen_h__"
  },
  {
    "path": "SoA/TestDisplacementMappingScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestDisplacementMappingScreen.h\"\n\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/graphics/ImageIO.h>\n\n#include \"Errors.h\"\n#include \"ShaderLoader.h\"\n\n#include <glm/gtx/transform.hpp>\n\nconst char* vertexShader = R\"(\n\nuniform mat4 unModelMatrix;\nuniform mat4 unMVP;\n\nin vec3 vPosition;\nin vec3 vNormal;\nin vec3 vTangent;\nin vec2 vUV;\n\nout vec3 fPosition;\nout vec2 fUV;\nout mat3 fTbnMatrix;\n\nvoid main()\n{\n    fPosition = (unModelMatrix * vec4(vPosition, 1.0)).xyz;\n    fUV = vec2(vUV.x, vUV.y);\n\n    vec3 normal = normalize((unModelMatrix * vec4(vNormal, 0.0)).xyz);\n    vec3 tangent = normalize((unModelMatrix * vec4(vTangent, 0.0)).xyz);\n    tangent = normalize(tangent - dot(tangent, normal) * normal);\t\n    vec3 biTangent = cross(tangent, normal);\n\n    fTbnMatrix = mat3(tangent, biTangent, normal);\n\n    gl_Position = unMVP * vec4(vPosition, 1.0);\n}\n)\";\n\nconst char* fragmentShader = R\"(\n\nuniform vec3 unEyePosition;\n\nuniform sampler2D unDiffuseTexture;\nuniform sampler2D unNormalTexture;\nuniform sampler2D unDispTexture;\n\nuniform float unDispScale;\n\nin vec3 fPosition;\nin vec2 fUV;\nin mat3 fTbnMatrix;\n\nout vec4 pColor;\n\nvec2 calculateOffset(vec2 uv, sampler2D dispTexture, mat3 tbnMatrix, vec3 directionToEye, float scale, float bias)\n{\n    return (directionToEye * tbnMatrix).xy * (texture(dispTexture, uv).r * scale + bias);\n}\n\nvoid main()\n{\n    vec3 directionToEye = normalize(unEyePosition - fPosition);\n    float bias = -unDispScale / 2.0;\n    vec2 offsetUV = fUV;\n    if (gl_FragCoord.x > 1920 / 2.0) offsetUV += calculateOffset(fUV, unDispTexture, fTbnMatrix, directionToEye, unDispScale, bias);\n    \n    vec3 correctNormal = fTbnMatrix[2];\n    if (gl_FragCoord.y > 1080.0 / 2.0)  correctNormal = fTbnMatrix * normalize(texture2D(unNormalTexture, offsetUV).rgb * 2.0 - 1.0);\n\n    vec3 directionToLight = vec3(0.0, 0.0, -2.5) - fPosition;\n    float light = dot(correctNormal, normalize(directionToLight)) / (length(directionToLight) + 1.0) * 4.0;\n\n    pColor = vec4(texture(unDiffuseTexture, offsetUV).rgb * light, 1.0);\n}\n\n)\";\n\ni32 TestDisplacementMappingScreen::getNextScreen() const\n{\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestDisplacementMappingScreen::getPreviousScreen() const\n{\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestDisplacementMappingScreen::build()\n{\n\n}\nvoid TestDisplacementMappingScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED)\n{\n\n}\n\nvoid TestDisplacementMappingScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED)\n{\n    m_displacementScale = 0.08f;\n    m_view = f32v3(0.0f);\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onWheel, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseWheelEvent& e) {\n        m_displacementScale += e.dy * 0.01f;\n        if (m_displacementScale < 0.0f) m_displacementScale = 0.0f;\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::LEFT) m_ldown = true;\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::LEFT) m_ldown = false;\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onMotion, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseMotionEvent& e) {\n        if (m_ldown) {\n            m_view.x += e.dy * 0.1f;\n            m_view.y += e.dx * 0.1f;\n        }\n    });\n\n    m_camera.setPosition(f64v3(0.0f, 0.0f, 0.0f));\n    m_camera.setFieldOfView(90.0f);\n    m_camera.setAspectRatio(m_game->getWindow().getAspectRatio());\n    m_camera.setDirection(f32v3(0.0f, 0.0f, -1.0f));\n    m_camera.setUp(f32v3(0.0f, 1.0f, 0.0f));\n    m_camera.setRight(f32v3(1.0f, 0.0f, 0.0f));\n    m_camera.setClippingPlane(0.1f, 16.0f);\n    m_camera.update();\n    \n    m_program = ShaderLoader::createProgram(\"ParallaxDisplacementMapping\", vertexShader, fragmentShader);\n\n    vg::BitmapResource rs = vg::ImageIO().load(\"Textures/Test/stone.png\");\n    if (rs.data == nullptr) pError(\"Failed to load texture\");\n    m_diffuseTexture = vg::GpuMemory::uploadTexture(&rs, vg::TexturePixelType::UNSIGNED_BYTE, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n    vg::ImageIO().free(rs);\n\n    rs = vg::ImageIO().load(\"Textures/Test/stone_NRM.png\");\n    if (rs.data == nullptr) pError(\"Failed to load texture\");\n    m_normalTexture = vg::GpuMemory::uploadTexture(&rs, vg::TexturePixelType::UNSIGNED_BYTE, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n    vg::ImageIO().free(rs);\n\n    rs = vg::ImageIO().load(\"Textures/Test/stone_DISP.png\");\n    if (rs.data == nullptr) pError(\"Failed to load texture\");\n    m_displacementTexture = vg::GpuMemory::uploadTexture(&rs, vg::TexturePixelType::UNSIGNED_BYTE, vg::TextureTarget::TEXTURE_2D, &vg::SamplerState::LINEAR_WRAP_MIPMAP);\n    vg::ImageIO().free(rs);\n\n    float anisotropy;\n    glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy);\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D, m_diffuseTexture);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);\n\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, m_normalTexture);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);\n\n    glActiveTexture(GL_TEXTURE2);\n    glBindTexture(GL_TEXTURE_2D, m_displacementTexture);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);\n}\n\nvoid TestDisplacementMappingScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED)\n{\n    m_program.dispose();\n    glDeleteTextures(1, &m_diffuseTexture);\n    glDeleteTextures(1, &m_normalTexture);\n    glDeleteTextures(1, &m_displacementTexture);\n}\n\nvoid TestDisplacementMappingScreen::update(const vui::GameTime& gameTime VORB_UNUSED)\n{\n\n}\n\nvoid TestDisplacementMappingScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED)\n{\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    m_program.use();\n    //m_displacementScale = (sinf(gameTime.total * 4.0) * 0.5f + 0.5f) * 0.1f;\n\n    f32m4 unModelMatrix = glm::translate(f32v3(0.0f, 0.0f, -3.0f - m_view.z)) * glm::rotate(m_view.x, f32v3(1.0f, 0.0f, 0.0f)) * glm::rotate(m_view.y, f32v3(0.0f, 1.0f, 0.0f));\n    glUniformMatrix4fv(m_program.getUniform(\"unModelMatrix\"), 1, false, (f32*)&unModelMatrix[0][0]);\n    f32m4 unMVP = m_camera.getViewProjectionMatrix() * unModelMatrix;\n    glUniformMatrix4fv(m_program.getUniform(\"unMVP\"), 1, false, (f32*)&unMVP[0][0]);\n\n    glUniform3f(m_program.getUniform(\"unEyePosition\"), (f32)m_camera.getPosition().x,\n                (f32)m_camera.getPosition().y,\n                (f32)m_camera.getPosition().z);\n    glUniform1i(m_program.getUniform(\"unDiffuseTexture\"), 0);\n    glUniform1i(m_program.getUniform(\"unNormalTexture\"), 1);\n    glUniform1i(m_program.getUniform(\"unDispTexture\"), 2);\n\n    glUniform1f(m_program.getUniform(\"unDispScale\"), m_displacementScale);\n\n    glBegin(GL_QUADS);\n    float tangentDir = 1.0f;\n    glVertexAttrib3f(0, -1.0f, 1.0f, 0.0f);\n    glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f);\n    glVertexAttrib3f(2, 0.0f, tangentDir, 0.0f);\n    glVertexAttrib2f(3, 0.0f, 0.0f);\n\n    glVertexAttrib3f(0, -1.0f, -1.0f, 0.0f);\n    glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f);\n    glVertexAttrib3f(2, 0.0f, tangentDir, 0.0f);\n    glVertexAttrib2f(3, 0.0f, 1.0f);\n\n    glVertexAttrib3f(0, 1.0f, -1.0f, 0.0f);\n    glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f);\n    glVertexAttrib3f(2, 0.0f, tangentDir, 0.0f);\n    glVertexAttrib2f(3, 1.0f, 1.0f);\n\n    glVertexAttrib3f(0, 1.0f, 1.0f, 0.0f);\n    glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f);\n    glVertexAttrib3f(2, 0.0f, tangentDir, 0.0f);\n    glVertexAttrib2f(3, 1.0f, 0.0f);\n\n    glEnd();\n    \n    m_program.unuse();\n    checkGlError(\"TestDisplacementMappingScreen::draw\");\n}\n"
  },
  {
    "path": "SoA/TestDisplacementMappingScreen.h",
    "content": "#pragma once\n\n#ifndef TestDisplacementMappingScreen_h__\n#define TestDisplacementMappingScreen_h__\n\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/graphics/GLProgram.h>\n\n#include \"Camera.h\"\n\nclass TestDisplacementMappingScreen : public vui::IGameScreen\n{\npublic:\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\nprivate:\n    Camera m_camera;\n    vg::GLProgram m_program;\n    VGTexture m_diffuseTexture;\n    VGTexture m_normalTexture;\n    VGTexture m_displacementTexture;\n    float m_displacementScale;\n\n    AutoDelegatePool m_hooks;\n    bool m_ldown;\n    f32v3 m_view;\n};\n\n#endif"
  },
  {
    "path": "SoA/TestGasGiantScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestGasGiantScreen.h\"\n#include \"soaUtils.h\"\n#include \"Errors.h\"\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/Timing.h>\n\n#include <iostream>\n\ni32 TestGasGiantScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestGasGiantScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestGasGiantScreen::build() {\n\n}\nvoid TestGasGiantScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n\n}\n\nvoid TestGasGiantScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        if(e.keyCode==VKEY_F1)\n        {\n            m_gasGiantRenderer.dispose();\n            m_gasGiantRenderer.initGL();\n            m_atmoRenderer.dispose();\n            m_atmoRenderer.initGL();\n        }\n        else if(e.keyCode==VKEY_A)\n        {\n            m_isAtmosphere=!m_isAtmosphere;\n        }\n        else if(e.keyCode==VKEY_ESCAPE)\n        {\n            exit(0);\n        }\n    });\n\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onWheel, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseWheelEvent& e) {\n        m_eyeDist += -e.dy * 0.025 * m_eyeDist;\n    });\n\n    glEnable(GL_DEPTH_TEST);\n\n//    vg::BitmapResource rs = vg::ImageIO().load(\"Textures/Test/GasGiantLookup2.png\");\n//    if (rs.data == nullptr) pError(\"Failed to load gas giant texture\");\n//    VGTexture colorBandLookup = vg::GpuMemory::uploadTexture(&rs,\n//                                                             vg::TexturePixelType::UNSIGNED_BYTE,\n//                                                             vg::TextureTarget::TEXTURE_2D,\n//                                                             &vg::SamplerState::LINEAR_CLAMP);\n//\n//    vg::ImageIO().free(rs);\n\n    glClearColor(0, 0, 0, 1);\n    glClearDepth(1.0);\n\n    m_eyePos = f32v3(0, 0, m_eyeDist);\n\n    // Set up components\n    m_ggCmp.radius = (f32)GIANT_RADIUS;\n    m_ggCmp.oblateness=0.0;\n    m_ggCmp.colorMapPath=\"Textures/Test/GasGiantLookup2.png\";\n\n    m_aCmp.radius = (f32)(GIANT_RADIUS * 1.025);\n    m_aCmp.planetRadius = (f32)GIANT_RADIUS;\n    m_aCmp.invWavelength4 = f32v3(1.0f / powf(0.475f, 4.0f),\n                                  1.0f / powf(0.57f, 4.0f),\n                                  1.0f / powf(0.65f, 4.0f));\n\n    m_camera.setFieldOfView(90.0f);\n    f32 width = (f32)m_game->getWindow().getWidth();\n    f32 height = (f32)m_game->getWindow().getHeight();\n    m_camera.setAspectRatio(width / height);\n    m_camera.setDirection(f32v3(0.0f, 0.0f, -1.0f));\n    m_camera.setUp(f32v3(0.0f, 1.0f, 0.0f));\n\n    m_gasGiantRenderer.initGL();\n    m_atmoRenderer.initGL();\n}\n\nvoid TestGasGiantScreen::onExit(const vui::GameTime& gameTime VORB_UNUSED) {\n\n}\n\nvoid TestGasGiantScreen::update(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_eyePos = f64v3(0, 0, GIANT_RADIUS + m_eyeDist + 100.0);\n}\n\nvoid TestGasGiantScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    m_camera.setClippingPlane((f32)(m_eyeDist / 2.0), (f32)(m_eyeDist + GIANT_RADIUS * 10.0));\n    m_camera.setPosition(f64v3(m_eyePos));\n    m_camera.update();\n\n    f32v3 lightPos = glm::normalize(f32v3(0.0f, 0.0f, 1.0f));\n\n    PreciseTimer timer;\n     m_gasGiantRenderer.draw(m_ggCmp, 0, m_camera.getViewProjectionMatrix(),\n                             f64q(), f32v3(m_eyePos), lightPos,\n                             computeZCoef(m_camera.getFarClip()),\n                             &m_slCmp, &m_aCmp);\n\n    if(m_isAtmosphere)\n        m_atmoRenderer.draw(m_aCmp, m_camera.getViewProjectionMatrix(), f32v3(m_eyePos), lightPos,\n                            computeZCoef(m_camera.getFarClip()), &m_slCmp);\n    //glFinish();\n   \n    checkGlError(\"TestGasGiantScreen::draw\");\n}\n"
  },
  {
    "path": "SoA/TestGasGiantScreen.h",
    "content": "#pragma once\n\n#ifndef TestGasGiantScreen_h__\n#define TestGasGiantScreen_h__\n\n#include \"AtmosphereComponentRenderer.h\"\n#include \"Camera.h\"\n#include \"GasGiantComponentRenderer.h\"\n#include \"SpaceSystemComponents.h\"\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/TextureCache.h>\n#include <Vorb/Event.hpp>\n\n#include <vector>\n\nclass GasGiantRenderer;\n\nDECL_VIO(class IOManager);\n\nclass TestGasGiantScreen : public vui::IGameScreen {\npublic:\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\n\nprivate:\n    const f64 GIANT_RADIUS = 154190.0 / 2.0;\n    GasGiantComponentRenderer m_gasGiantRenderer;\n    AtmosphereComponentRenderer m_atmoRenderer;\n    f64v3 m_eyePos;\n    f64 m_eyeDist = GIANT_RADIUS;\n    GasGiantComponent m_ggCmp;\n    SpaceLightComponent m_slCmp;\n    AtmosphereComponent m_aCmp;\n    Camera m_camera;\n    AutoDelegatePool m_hooks;\n    bool m_isAtmosphere=true;\n};\n\n#endif"
  },
  {
    "path": "SoA/TestMappingScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestMappingScreen.h\"\n\n#include <Vorb/graphics/GLStates.h>\n#include <glm/gtc/matrix_transform.hpp>\n\n#ifdef _MSC_VER\n#pragma region Simple shader code\n#endif// _MSC_VER\nconst cString SRC_VERT = R\"(\nuniform mat4 unWVP;\n\nin vec4 vPosition;\n\nvoid main() {\n    gl_Position = unWVP * vPosition;\n}\n)\";\nconst cString SRC_FRAG = R\"(\nout vec4 pColor;\n\nvoid main() {\n    pColor = vec4(1, 0, 0, 1);\n}\n)\";\n#ifdef _MSC_VER\n#pragma endregion\n#endif// _MSC_VER\n\n// Number cells per row/column in a single grid\nconst ui32 CELLS = 30;\n\ni32 TestMappingScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\ni32 TestMappingScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestMappingScreen::build() {\n    // Empty\n}\nvoid TestMappingScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestMappingScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    buildGeometry();\n\n    m_program.init();\n    m_program.addShader(vg::ShaderType::VERTEX_SHADER, SRC_VERT);\n    m_program.addShader(vg::ShaderType::FRAGMENT_SHADER, SRC_FRAG);\n    m_program.link();\n    m_program.initAttributes();\n    m_program.initUniforms();\n\n    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);\n    glClearDepth(1.0);\n}\nvoid TestMappingScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    glDeleteBuffers(1, &m_verts);\n    glDeleteBuffers(1, &m_inds);\n    m_program.dispose();\n}\n\nvoid TestMappingScreen::update(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\nvoid TestMappingScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    f32m4 mWVP = glm::perspectiveFov(90.0f, 800.0f, 600.0f, 0.1f, 100.0f) * glm::lookAt(f32v3(0, 0, 10), f32v3(0, 0, 0), f32v3(0, 1, 0)) ;\n\n    vg::DepthState::FULL.set();\n    vg::RasterizerState::CULL_CLOCKWISE.set();\n\n    m_program.use();\n    m_program.enableVertexAttribArrays();\n\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, false, (f32*)&mWVP[0][0]);\n\n    glBindBuffer(GL_ARRAY_BUFFER, m_verts);\n    glVertexAttribPointer(m_program.getAttribute(\"vPosition\"), 3, GL_FLOAT, false, 0, nullptr);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_inds);\n    glDrawElements(GL_TRIANGLES, m_indexCount, GL_UNSIGNED_INT, nullptr);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    m_program.disableVertexAttribArrays();\n    vg::GLProgram::unuse();\n}\n\nvoid TestMappingScreen::buildGeometry() {\n    // Make vertices\n    ui32 cellPoints = CELLS + 1;\n    ui32 gridPoints = cellPoints * cellPoints;\n    f32v3* verts = new f32v3[gridPoints * 2];\n    size_t i = 0;\n    for (size_t y = 0; y < cellPoints; y++) {\n        for (size_t x = 0; x < cellPoints; x++) {\n            f32v3 pos((f32)x / (f32)CELLS, 0, (f32)y / (f32)CELLS);\n            pos.x -= 0.5f;\n            pos.x *= 2.0f;\n            pos.z -= 0.5f;\n            pos.z *= 2.0f;\n            pos.x = glm::sign(pos.x) * (sin(abs(pos.x) * 1.57079f));\n            pos.z = glm::sign(pos.z) * (sin(abs(pos.z) * 1.57079f));\n\n            f32 lp = glm::length(pos);\n            if (lp < 0.00001) {\n                pos.y = 1.0f;\n            } else {\n                f32 d = std::max(abs(pos.x), abs(pos.z));\n                pos /= lp;\n                pos *= d;\n                pos.y = sin(acos(d));\n            }\n\n            verts[i] = pos;\n            pos.y = -pos.y;\n            verts[gridPoints + i] = pos;\n            i++;\n        }\n    }\n\n    // Make indices\n    ui32 gridInds = 6 * CELLS * CELLS;\n    m_indexCount = gridInds * 2;\n    ui32* inds = new ui32[m_indexCount];\n    i = 0;\n    for (size_t y = 0; y < CELLS; y++) {\n        for (size_t x = 0; x < CELLS; x++) {\n            ui32 vi = y * cellPoints + x;\n            inds[i] = vi;\n            inds[i + 1] = vi + cellPoints;\n            inds[i + 2] = vi + 1;\n            inds[i + 3] = vi + 1;\n            inds[i + 4] = vi + cellPoints;\n            inds[i + 5] = vi + cellPoints + 1;\n\n            vi += gridPoints;\n            inds[gridInds + i] = vi;\n            inds[gridInds + i + 1] = vi + 1;\n            inds[gridInds + i + 2] = vi + cellPoints;\n            inds[gridInds + i + 3] = vi + cellPoints;\n            inds[gridInds + i + 4] = vi + 1;\n            inds[gridInds + i + 5] = vi + cellPoints + 1;\n\n            i += 6;\n        }\n    }\n\n    // Fill buffers\n    glGenBuffers(1, &m_verts);\n    glBindBuffer(GL_ARRAY_BUFFER, m_verts);\n    glBufferData(GL_ARRAY_BUFFER, gridPoints * 2 * sizeof(f32v3), verts, GL_STATIC_DRAW);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    delete[] verts;\n    glGenBuffers(1, &m_inds);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_inds);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(ui32), inds, GL_STATIC_DRAW);\n    delete[] inds;\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n}\n"
  },
  {
    "path": "SoA/TestMappingScreen.h",
    "content": "///\n/// TestMappingScreen.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 14 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Render test of grid-mapped sphere\n///\n\n#pragma once\n\n#ifndef TestMappingScreen_h__\n#define TestMappingScreen_h__\n\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/gtypes.h>\n\nclass TestMappingScreen : public vui::IGameScreen {\npublic:\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\nprivate:\n    void buildGeometry();\n\n    VGVertexBuffer m_verts; ///< Sphere's vertex buffer (of positions)\n    VGIndexBuffer m_inds; ///< Sphere's index buffer\n    ui32 m_indexCount; ///< Number of indices for sphere\n    vg::GLProgram m_program; ///< Basic rendering program\n};\n\n#endif // TestMappingScreen_h__"
  },
  {
    "path": "SoA/TestNewBlockAPIScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestNewBlockAPIScreen.h\"\n\n#include \"Positional.h\"\n\ni32 TestNewBlockAPIScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\ni32 TestNewBlockAPIScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestNewBlockAPIScreen::build() {\n    // Empty\n}\nvoid TestNewBlockAPIScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestNewBlockAPIScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    VoxelIterablePosition pos { 0, 1, 2 };\n    printf(\"Pos: %d,%d,%d\\n\", pos.x, pos.y, pos.z);\n    pos.x += 5;\n    printf(\"Pos: %d,%d,%d\\n\", pos.x, pos.y, pos.z);\n    pos.x += 35;\n    printf(\"Pos: %d,%d,%d\\n\", pos.x, pos.y, pos.z);\n    pos.wx() += 0;\n    printf(\"Pos: %d,%d,%d\\n\", pos.x, pos.y, pos.z);\n    pos.cx() += 200;\n    printf(\"Pos: %d,%d,%d\\n\", pos.x, pos.y, pos.z);\n    (pos.wx() += 200).rz() += 200;\n    printf(\"Pos: %d,%d,%d\\n\", pos.x, pos.y, pos.z);\n}\nvoid TestNewBlockAPIScreen::onExit(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestNewBlockAPIScreen::update(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\nvoid TestNewBlockAPIScreen::draw(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n"
  },
  {
    "path": "SoA/TestNewBlockAPIScreen.h",
    "content": "//\n// TestNewBlockAPIScreen.h\n// Seed of Andromeda\n//\n// Created by Cristian Zaloj on 26 May 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef TestNewBlockAPIScreen_h__\n#define TestNewBlockAPIScreen_h__\n\n#include <Vorb/ui/IGameScreen.h>\n\nclass TestNewBlockAPIScreen : public vui::IGameScreen {\npublic:\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\n};\n\n#endif // TestNewBlockAPIScreen_h__\n"
  },
  {
    "path": "SoA/TestNoiseScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestNoiseScreen.h\"\n\n#include <Vorb/ui/InputDispatcher.h>\n#include <SDL2/SDL.h>\n#include <Vorb/colors.h>\n#include <Vorb/graphics/GpuMemory.h>\n\n#include \"Errors.h\"\n#include \"ShaderLoader.h\"\n#include \"Noise.h\"\n#include \"soaUtils.h\"\n\n#define MS_AVARAGE_FRAMES 60\n\nauto startTime = std::chrono::high_resolution_clock::now();\n\nf64 ms = 0;\nunsigned int frameCount = 0;\n\nTestNoiseScreen::TestNoiseScreen(const App* app) :\nIAppScreen<App>(app) {\n\n}\n\ni32 TestNoiseScreen::getNextScreen() const\n{\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestNoiseScreen::getPreviousScreen() const\n{\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestNoiseScreen::build()\n{\n\n}\nvoid TestNoiseScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED)\n{\n\n}\n\nvoid TestNoiseScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED)\n{ \n    m_sb.init();\n    m_font.init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n\n    for (int i = 0; i < NUM_TEST_NOISE_TYPES; i++) {\n        m_textures[i] = 0;\n    }\n\n    onNoiseChange();\n\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        if (e.keyCode == VKEY_LEFT) {\n            if (m_currentNoise == 0) {\n                m_currentNoise = TEST_NOISE_TYPES::CELLULAR;\n            } else {\n                m_currentNoise = (TEST_NOISE_TYPES)((int)m_currentNoise - 1);\n            }\n        }\n        if (e.keyCode == VKEY_RIGHT) {\n            if (m_currentNoise == TEST_NOISE_TYPES::CELLULAR) {\n                m_currentNoise = TEST_NOISE_TYPES::SIMPLEX;\n            } else {\n                m_currentNoise = (TEST_NOISE_TYPES)((int)m_currentNoise + 1);\n            }\n        }\n        onNoiseChange();\n    });\n}\n\nvoid TestNoiseScreen::onExit(const vui::GameTime& gameTime VORB_UNUSED)\n{\n}\n\nvoid TestNoiseScreen::update(const vui::GameTime& gameTime VORB_UNUSED)\n{\n}\n\nvoid TestNoiseScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED)\n{\n    \n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    int numSamples = m_app->getWindow().getWidth() * (m_app->getWindow().getHeight() - 100);\n\n    f32v2 destDims = f32v2(m_app->getWindow().getViewportDims());\n    destDims.y += 100.0f;\n\n    // Texture\n    m_sb.begin();\n    m_sb.draw(m_textures[m_currentNoise], f32v2(0.0f, 100.0f), destDims, color::White);\n    m_sb.end();\n    m_sb.render(f32v2(m_app->getWindow().getViewportDims()));\n\n    // UI\n    m_sb.begin();\n    switch (m_currentNoise) {\n        case SIMPLEX:\n            m_sb.drawString(&m_font, \"Simplex\", f32v2(30.0f), f32v2(0.7f), color::White);\n            break;\n        case CELLULAR:\n            m_sb.drawString(&m_font, \"Cellular\", f32v2(30.0f), f32v2(0.7f), color::White);\n            break;\n    }\n    char buf[256];\n    sprintf(buf, \"Time %.2lf ms\", m_times[m_currentNoise]);\n    m_sb.drawString(&m_font, buf, f32v2(30.0f, 60.0f), f32v2(0.7f), color::White);\n\n    sprintf(buf, \"Samples %d\", numSamples);\n    m_sb.drawString(&m_font, buf, f32v2(330.0f, 60.0f), f32v2(0.7f), color::White);\n\n    sprintf(buf, \"Time per sample: %.6lf ms\", m_times[m_currentNoise] / numSamples);\n    m_sb.drawString(&m_font, buf, f32v2(630.0f, 60.0f), f32v2(0.7f), color::White);\n\n    m_sb.end();\n    m_sb.render(f32v2(m_app->getWindow().getViewportDims()));\n\n}\n\nvoid TestNoiseScreen::onNoiseChange()\n{\n    // Only generate once\n    if (m_textures[m_currentNoise]) return;\n    const f64 frequency = 0.01;\n    int width = m_app->getWindow().getWidth();\n    int height = m_app->getWindow().getHeight() - 100;\n    std::vector<color4> buffer;\n    buffer.resize(width * height);\n    PreciseTimer timer;\n    timer.start();\n    f64 val;\n    ui8 p;\n    f64v2 cval;\n    switch (m_currentNoise) {\n        case SIMPLEX:\n            for (int y = 0; y < height; y++) {\n                for (int x = 0; x < width; x++) {\n                    val = Noise::raw((f64)x * frequency, (f64)y * frequency, 0.0);\n                    p = (ui8)((val + 1.0) * 127.5);\n                    buffer[y * width + x].r = p;\n                    buffer[y * width + x].g = p;\n                    buffer[y * width + x].b = p;\n                    buffer[y * width + x].a = 255;\n                }\n            }\n            break;\n        case CELLULAR:\n            for (int y = 0; y < height; y++) {\n                for (int x = 0; x < width; x++) {\n                    cval = Noise::cellular(f64v3((f64)x * frequency, (f64)y * frequency, 0.0));\n                    val = (cval.y - cval.x);\n                    p = (ui8)((val + 1.0) * 127.5);\n                    buffer[y * width + x].r = p;\n                    buffer[y * width + x].g = p;\n                    buffer[y * width + x].b = p;\n                    buffer[y * width + x].a = 255;\n                }\n            }\n            break;\n    }\n    m_times[m_currentNoise] = timer.stop();\n    m_textures[m_currentNoise] = vg::GpuMemory::uploadTexture((void*)buffer.data(), width, height);\n}"
  },
  {
    "path": "SoA/TestNoiseScreen.h",
    "content": "#pragma once\n\n#ifndef TestNoiseScreen_h__\n#define TestNoiseScreen_h__\n\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/Timing.h>\n#include <Vorb/graphics/SpriteBatch.h>\n\n#include \"App.h\"\n\nconst int NUM_TEST_NOISE_TYPES = 2;\nenum TEST_NOISE_TYPES { SIMPLEX = 0, CELLULAR };\n\nclass TestNoiseScreen : public vui::IAppScreen <App>\n{\npublic:\n    TestNoiseScreen(const App* app);\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\nprivate:\n    void onNoiseChange();\n    vg::SpriteBatch m_sb;\n    vg::SpriteFont m_font;\n    TEST_NOISE_TYPES m_currentNoise = SIMPLEX;\n    FpsLimiter m_limiter;\n    AutoDelegatePool m_hooks;\n    VGTexture m_textures[NUM_TEST_NOISE_TYPES];\n    f64 m_times[NUM_TEST_NOISE_TYPES];\n};\n\n#endif"
  },
  {
    "path": "SoA/TestPlanetGenScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestPlanetGenScreen.h\"\n\n#include \"soaUtils.h\"\n#include \"SpaceSystemAssemblages.h\"\n#include \"Errors.h\"\n#include \"ShaderLoader.h\"\n#include \"SoaEngine.h\"\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/Timing.h>\n\n#include <iostream>\n\ni32 TestPlanetGenScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestPlanetGenScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestPlanetGenScreen::build() {\n\n}\nvoid TestPlanetGenScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n\n}\n\nvoid TestPlanetGenScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        if (e.keyCode == VKEY_F1) {\n            m_terrainRenderer.dispose();\n            m_terrainRenderer.initGL();\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onWheel, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseWheelEvent& e) {\n        m_eyeDist += -e.dy * 0.025 * m_eyeDist;\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        if (e.keyCode == VKEY_ESCAPE) {\n            exit(0);\n        }\n    });\n    glEnable(GL_DEPTH_TEST);\n    glClearColor(1, 0, 0, 1);\n    glClearDepth(1.0);\n\n    m_terrainRenderer.initGL();\n    m_atmoRenderer.initGL();\n\n    SoaEngine::initState(&m_state);\n\n    m_eyePos = f32v3(0, 0, m_eyeDist);\n\n    TerrainPatchMesher::generateIndices();\n    { // Set up planet\n        SystemOrbitProperties props;\n        PlanetProperties pProps;\n        pProps.diameter = PLANET_RADIUS * 2.0;\n        pProps.mass = 10000.0;\n        PlanetGenLoader loader;\n        loader.init(&m_iom);\n        pProps.planetGenData = loader.loadPlanetGenData(\"StarSystems/Trinity/Moons/Aldrin/properties.yml\");\n        TerrainFuncProperties tprops;\n        tprops.low = 9;\n        tprops.high = 10;\n        pProps.planetGenData->radius = PLANET_RADIUS;\n        pProps.planetGenData->baseTerrainFuncs.funcs.setData(&tprops, 1);\n\n        SpaceSystemAssemblages::createPlanet(m_state.spaceSystem, &props, &pProps, &body, m_state.threadPool);\n\n    }\n    // Set camera properties\n    m_camera.setFieldOfView(90.0f);\n    f32 width = (f32)m_game->getWindow().getWidth();\n    f32 height = (f32)m_game->getWindow().getHeight();\n    m_camera.setAspectRatio(width / height);\n    m_camera.setDirection(f32v3(0.0f, 0.0f, -1.0f));\n    m_camera.setUp(f32v3(0.0f, 1.0f, 0.0f));\n}\n\nvoid TestPlanetGenScreen::onExit(const vui::GameTime& gameTime VORB_UNUSED) {\n\n}\n\nvoid TestPlanetGenScreen::update(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_eyePos = f64v3(0, 0, PLANET_RADIUS + m_eyeDist + 100.0);\n\n    m_updater.update(&m_state, m_eyePos, f64v3(0.0));\n    m_updater.glUpdate(&m_state);\n}\n\nvoid TestPlanetGenScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    m_camera.setClippingPlane((f32)(m_eyeDist / 2.0), (f32)(m_eyeDist + PLANET_RADIUS * 10.0));\n    m_camera.setPosition(f64v3(m_eyePos));\n    m_camera.update();\n\n    f32v3 lightPos = glm::normalize(f32v3(0.0f, 0.0f, 1.0f));\n\n    PreciseTimer timer;\n    auto& aCmp = m_state.spaceSystem->atmosphere.getFromEntity(body.entity);\n    auto& arCmp = m_state.spaceSystem->axisRotation.getFromEntity(body.entity);\n    m_terrainRenderer.draw(m_state.spaceSystem->sphericalTerrain.getFromEntity(body.entity), &m_camera, lightPos,\n                           f64v3(0.0f/*m_eyePos*/), computeZCoef(m_camera.getFarClip()), &m_slCmp,\n                           &arCmp, &aCmp);\n\n    m_atmoRenderer.draw(m_state.spaceSystem->atmosphere.getFromEntity(body.entity), m_camera.getViewProjectionMatrix(), f32v3(m_eyePos), lightPos,\n                        computeZCoef(m_camera.getFarClip()), &m_slCmp);\n    //glFinish();\n\n    checkGlError(\"TestGasGiantScreen::draw\");\n}\n"
  },
  {
    "path": "SoA/TestPlanetGenScreen.h",
    "content": "///\n/// TestPlanetGenScreen.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 26 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Screen for testing planet generation\n///\n\n#pragma once\n\n#ifndef TestPlanetGenScreen_h__\n#define TestPlanetGenScreen_h__\n\n#include \"AtmosphereComponentRenderer.h\"\n#include \"Camera.h\"\n#include \"SpaceSystem.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"SpaceSystemUpdater.h\"\n#include \"SphericalTerrainComponentRenderer.h\"\n#include \"SphericalTerrainComponentUpdater.h\"\n#include \"PlanetGenLoader.h\"\n#include \"SoAState.h\"\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/VorbPreDecl.inl>\n#include <Vorb/graphics/TextureCache.h>\n#include <Vorb/Event.hpp>\n\n#include <vector>\n\nclass TestPlanetGenScreen : public vui::IGameScreen {\npublic:\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\n\nprivate:\n    const f64 PLANET_RADIUS = 6000.0;\n    SphericalTerrainComponentRenderer m_terrainRenderer;\n    AtmosphereComponentRenderer m_atmoRenderer;\n    SystemBody body;\n    f64v3 m_eyePos;\n    f64 m_eyeDist = PLANET_RADIUS;\n    SpaceSystemUpdater m_updater;\n    SpaceLightComponent m_slCmp;\n    Camera m_camera;\n    AutoDelegatePool m_hooks;\n    vio::IOManager m_iom;\n    SoaState m_state;\n};\n\n#endif // TestPlanetGenScreen_h__"
  },
  {
    "path": "SoA/TestScriptScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestScriptScreen.h\"\n\n#include <Vorb/io/File.h>\n#include <Vorb/io/Path.h>\n#include <Vorb/ui/InputDispatcher.h>\n\n#include \"App.h\"\n#include \"InputMapper.h\"\n#include \"Inputs.h\"\n\nTestScriptScreen::TestScriptScreen(const App* app, CommonState* state) : IAppScreen<App>(app),\n    m_commonState(state)\n{\n    // Empty\n}\n\ni32 TestScriptScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestScriptScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestScriptScreen::build() {\n    // Empty\n}\n\nvoid TestScriptScreen::destroy(const vui::GameTime&) {\n    // Empty\n}\n\nvoid TestScriptScreen::onEntry(const vui::GameTime&) {\n    m_env.init();\n\n    m_env.setNamespaces(\"onMessage\");\n    m_env.addCDelegate(\"subscribe\", makeFunctor([&](nString name) {\n        onMessage.add(m_env.template getScriptDelegate<void, Sender, nString>(name), true);\n    }));\n    m_env.addCDelegate(\"unsubscribe\", makeFunctor([&](nString name) {\n        onMessage.remove(m_env.template getScriptDelegate<void, Sender, nString>(name, false));\n    }));\n    m_env.setNamespaces();\n\n    m_env.addCDelegate(\"C_Print\", makeDelegate(&TestScriptScreen::printMessage));\n    m_env.addCDelegate(\"C_Add\",   makeDelegate(&TestScriptScreen::add));\n\n    m_env.run(vio::Path(\"test.lua\"));\n\n    auto del = m_env.getScriptDelegate<void, Sender, nString>(\"doPrint\");\n\n    onMessage(\"Hello, World!\");\n    onMessage(\"Hello, World!\");\n\n    del.invoke(nullptr, \"Hello, Waldo!\");\n\n    m_sb.init();\n    m_font.init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n\n    m_ui.init(this, m_commonState->window, nullptr, &m_font, &m_sb);\n\n    auto view = m_ui.makeView(\"TestView\", 1);\n    view.viewEnv->getEnv()->addCDelegate(\"C_Print\", makeDelegate(&TestScriptScreen::printMessage));\n    view.viewEnv->run(\"ui_test.lua\");\n}\n\nvoid TestScriptScreen::onExit(const vui::GameTime&) {\n    // Empty\n}\n\nvoid TestScriptScreen::update(const vui::GameTime& dt) {\n    m_ui.update((f32)dt.elapsed);\n}\n\nvoid TestScriptScreen::draw(const vui::GameTime&) {\n    glClear(GL_COLOR_BUFFER_BIT);\n\n    m_ui.draw();\n}"
  },
  {
    "path": "SoA/TestScriptScreen.h",
    "content": "#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/ui/IGameScreen.h>\n\n#include <iostream>\n\n#include <Vorb/Event.hpp>\n#include <Vorb/script/lua/Environment.h>\n#include <Vorb/ui/ScriptedUI.h>\n\n#include \"CommonState.h\"\n\nclass InputMapper;\n\nclass TestScriptScreen : public vui::IAppScreen<App> {\npublic:\n    TestScriptScreen(const App* app, CommonState* state);\n\n    i32 getNextScreen() const override;\n    i32 getPreviousScreen() const override;\n\n    void build() override;\n    void destroy(const vui::GameTime&) override;\n\n    void onEntry(const vui::GameTime&) override;\n    void onExit(const vui::GameTime&) override;\n\n    void update(const vui::GameTime&) override;\n    void draw(const vui::GameTime&) override;\n\n    Event<nString> onMessage;\n\n    static void printMessage(nString message) {\n        std::cout << message << std::endl;\n    }\n\n    static i32 add(i32 a, i32 b) {\n        return a + b;\n    }\nprivate:\n    CommonState*               m_commonState;\n    vscript::lua::Environment  m_env;\n    vui::ScriptedUI<vscript::lua::Environment> m_ui;\n    vg::SpriteBatch m_sb;\n    vg::SpriteFont m_font;\n};\n"
  },
  {
    "path": "SoA/TestStarScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestStarScreen.h\"\n\n#include \"soaUtils.h\"\n#include \"Errors.h\"\n#include \"SoaOptions.h\"\n#include \"SoAState.h\"\n#include <Vorb/Timing.h>\n#include <Vorb/colors.h>\n#include <Vorb/graphics/DepthState.h>\n#include <Vorb/graphics/RasterizerState.h>\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GpuMemory.h>\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/io/IOManager.h>\n\n#include <iostream>\n\nTestStarScreen::TestStarScreen(const App* app) :\nIAppScreen<App>(app) {\n    m_modPathResolver.init(\"Textures/TexturePacks/\" + soaOptions.getStringOption(\"Texture Pack\").defaultValue + \"/\",\n                           \"Textures/TexturePacks/\" + soaOptions.getStringOption(\"Texture Pack\").value + \"/\");\n}\n\n\ni32 TestStarScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestStarScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestStarScreen::build() {\n\n}\nvoid TestStarScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n\n}\n\nvoid TestStarScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    m_starRenderer.init(&m_modPathResolver);\n    m_starRenderer.initGL();\n\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&](Sender s VORB_UNUSED, const vui::KeyEvent& e) {\n        if (e.keyCode == VKEY_F1) {\n            m_starRenderer.disposeShaders();\n            //m_hdr.reloadShader(); // dis is broked\n        } else if (e.keyCode == VKEY_UP) {\n            m_isUpDown = true;\n        } else if (e.keyCode == VKEY_DOWN) {\n            m_isDownDown = true;\n        } else if (e.keyCode == VKEY_H) {\n            m_isHDR = !m_isHDR;\n        } else if (e.keyCode == VKEY_G) {\n            m_isGlow = !m_isGlow;\n        } else if (e.keyCode == VKEY_1) {\n            m_is1Pressed = true;\n        } else if (e.keyCode == VKEY_2) {\n            m_is2Pressed = true;\n        } else if (e.keyCode == VKEY_3) {\n            m_is3Pressed = true;\n        } else if (e.keyCode == VKEY_4) {\n            m_is4Pressed = true;\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        if (e.keyCode == VKEY_UP) {\n            m_isUpDown = false;\n        } else if (e.keyCode == VKEY_DOWN) {\n            m_isDownDown = false;\n        } else if (e.keyCode == VKEY_1) {\n            m_is1Pressed = false;\n        } else if (e.keyCode == VKEY_2) {\n            m_is2Pressed = false;\n        } else if (e.keyCode == VKEY_3) {\n            m_is3Pressed = false;\n        } else if (e.keyCode == VKEY_4) {\n            m_is4Pressed = false;\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onWheel, [&](Sender s VORB_UNUSED, const vui::MouseWheelEvent& e) {\n        m_eyeDist += -e.dy * 0.05 * m_eyeDist;\n    });\n    glEnable(GL_DEPTH_TEST);\n\n    glClearColor(0, 0, 0, 1);\n    glClearDepth(1.0);\n\n    m_eyePos = f32v3(0, 0, STAR_RADIUS + 100.0 + m_eyeDist);\n\n    // Set up components\n    m_sCmp.radius = STAR_RADIUS;\n    m_sCmp.temperature = 5778.0;\n    m_sCmp.mass = 6.56172e29;\n\n    m_spriteBatch.init();\n    m_spriteFont.init(\"Fonts/orbitron_black-webfont.ttf\", 32);\n\n    m_hdrFrameBuffer = new vg::GLRenderTarget(m_game->getWindow().getViewportDims());\n    m_hdrFrameBuffer->init(vg::TextureInternalFormat::RGBA16F, 0).initDepth();\n\n    m_quad.init();\n    // TODO(Ben): BROKEN\n    //m_hdr.init(&m_quad, &m_camera);\n    m_hdr.hook(&m_quad);\n\n    m_camera.setFieldOfView(90.0f);\n    f32 width = (f32)m_game->getWindow().getWidth();\n    f32 height = (f32)m_game->getWindow().getHeight();\n    m_camera.setAspectRatio(width / height);\n    m_camera.setDirection(f32v3(0.0f, 0.0f, -1.0f));\n    m_camera.setUp(f32v3(0.0f, 1.0f, 0.0f));\n}\n\nvoid TestStarScreen::onExit(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    delete m_hdrFrameBuffer;\n}\n\nvoid TestStarScreen::update(const vui::GameTime& gameTime VORB_UNUSED) {\n    m_eyePos = f32v3(0, 0, STAR_RADIUS + 100.0 + m_eyeDist);\n\n    const float TMP_INC = 25.0;\n\n    if (m_isDownDown) {\n        m_sCmp.temperature -= TMP_INC;\n    } else if (m_isUpDown) {\n        m_sCmp.temperature += TMP_INC;\n    }\n\n    // TODO(Ben): Remove\n    //if (m_is1Pressed) graphicsOptions.hdrExposure -= 0.01f;\n    //if (m_is2Pressed) graphicsOptions.hdrExposure += 0.01f;\n    //if (m_is3Pressed) graphicsOptions.gamma -= 0.01f;\n    //if (m_is4Pressed) graphicsOptions.gamma += 0.01f;\n}\n\nvoid TestStarScreen::draw(const vui::GameTime& gameTime VORB_UNUSED) {\n\n    if (m_isHDR) m_hdrFrameBuffer->use();\n\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    m_camera.setClippingPlane((f32)(m_eyeDist / 2.0), (f32)(m_eyeDist + STAR_RADIUS * 10.0));\n    m_camera.setPosition(f64v3(m_eyePos)); \n    m_camera.update();\n\n    // Render the star\n    f32v3 fEyePos(m_eyePos);\n\n    f32 zCoef = computeZCoef(m_camera.getFarClip());\n    // TODO(Ben): render star first and figure out why depth testing is failing\n    m_starRenderer.drawCorona(m_sCmp, m_camera.getViewProjectionMatrix(), m_camera.getViewMatrix(), fEyePos, zCoef);\n    m_starRenderer.drawStar(m_sCmp, m_camera.getViewProjectionMatrix(), f64q(), fEyePos, zCoef);\n    glBlendFunc(GL_ONE, GL_ONE);\n    if (m_isGlow) m_starRenderer.drawGlow(m_sCmp, m_camera.getViewProjectionMatrix(), m_eyePos,\n                                           m_camera.getAspectRatio(), m_camera.getDirection(),\n                                           m_camera.getRight());\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    \n    \n    if (m_isHDR) {\n        glBindFramebuffer(GL_FRAMEBUFFER, 0);\n        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(m_hdrFrameBuffer->getTextureTarget(), m_hdrFrameBuffer->getTextureID());\n        m_hdr.render();\n    }\n\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        if (e.keyCode == VKEY_ESCAPE) {\n            exit(0);\n        }\n    });\n   \n    checkGlError(\"TestStarScreen::draw\");\n\n    // Draw the temperature and HDR\n    char buf[256];\n    sprintf(buf, \"Temperature (K): %.0lf\", m_sCmp.temperature);\n    m_spriteBatch.begin();\n    m_spriteBatch.drawString(&m_spriteFont, buf, f32v2(30.0f, 30.0f), f32v2(1.0f), color::AliceBlue);\n    sprintf(buf, \"Distance (KM): %.1lf\", m_eyeDist + 100.0);\n    m_spriteBatch.drawString(&m_spriteFont, buf, f32v2(30.0f, 65.0f), f32v2(1.0f), color::AliceBlue);\n    sprintf(buf, \"Distance (AU): %.4lf\", (m_eyeDist + 100.0) * 0.00000000668458712);\n    m_spriteBatch.drawString(&m_spriteFont, buf, f32v2(30.0f, 100.0f), f32v2(1.0f), color::AliceBlue);\n    if (m_isGlow) {\n        m_spriteBatch.drawString(&m_spriteFont, \"Glow: Enabled\", f32v2(30.0f, 135.0f), f32v2(1.0f), color::AliceBlue);\n    } else {\n        m_spriteBatch.drawString(&m_spriteFont, \"Glow: Disabled\", f32v2(30.0f, 135.0f), f32v2(1.0f), color::AliceBlue);\n    }\n    if (m_isHDR) {\n        m_spriteBatch.drawString(&m_spriteFont, \"HDR: Enabled\", f32v2(30.0f, 170.0f), f32v2(1.0f), color::AliceBlue);\n    // TODO(Ben): Remove\n        //   sprintf(buf, \"  Exposure (1,2): %.1lf\", (f64)graphicsOptions.hdrExposure);\n    //   m_spriteBatch.drawString(&m_spriteFont, buf, f32v2(30.0f, 205.0f), f32v2(1.0f), color::AliceBlue);\n    //   sprintf(buf, \"  Gamma (3,4): %.1lf\", (f64)graphicsOptions.gamma);\n    //  m_spriteBatch.drawString(&m_spriteFont, buf, f32v2(30.0f, 240.0f), f32v2(1.0f), color::AliceBlue);\n    } else {\n        m_spriteBatch.drawString(&m_spriteFont, \"HDR: Disabled\", f32v2(30.0f, 170.0f), f32v2(1.0f), color::AliceBlue);\n    }\n    \n    m_spriteBatch.end();\n\n\n    f32 width = (f32)m_game->getWindow().getWidth();\n    f32 height = (f32)m_game->getWindow().getHeight();\n    m_spriteBatch.render(f32v2(width, height));\n\n    vg::DepthState::FULL.set();\n    vg::RasterizerState::CULL_CLOCKWISE.set();\n}\n\n"
  },
  {
    "path": "SoA/TestStarScreen.h",
    "content": "///\n/// TestStarScreen.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 9 Apr 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Test screen for star renderer\n///\n\n#pragma once\n\n#ifndef TestStarScreen_h__\n#define TestStarScreen_h__\n\n#include \"StarComponentRenderer.h\"\n#include \"SpaceSystemComponents.h\"\n#include \"Camera.h\"\n#include \"HdrRenderStage.h\"\n#include \"ModPathResolver.h\"\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/FullQuadVBO.h>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/graphics/GLRenderTarget.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/ui/IGameScreen.h>\n\nclass HdrRenderStage;\nstruct SoaState;\nclass App;\n\nclass TestStarScreen : public vui::IAppScreen<App> {\npublic:\n    TestStarScreen(const App* app);\n    virtual ~TestStarScreen(){};\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\n\nprivate:\n    const f64 STAR_RADIUS = 696000;\n\n    StarComponentRenderer m_starRenderer;\n    f64v3 m_eyePos;\n    f64 m_eyeDist = STAR_RADIUS;\n    StarComponent m_sCmp;\n    bool m_isUpDown = false;\n    bool m_isDownDown = false;\n    AutoDelegatePool m_hooks;\n    vg::SpriteBatch m_spriteBatch;\n    vg::SpriteFont m_spriteFont;\n    HdrRenderStage m_hdr;\n    vg::FullQuadVBO m_quad;\n    Camera m_camera;\n    vg::GLRenderTarget* m_hdrFrameBuffer = nullptr;\n    ModPathResolver m_modPathResolver;\n    bool m_isHDR = true;\n    bool m_isGlow = true;\n    bool m_is1Pressed = false;\n    bool m_is2Pressed = false;\n    bool m_is3Pressed = false;\n    bool m_is4Pressed = false;\n};\n\n#endif // TestStarScreen_h__\n"
  },
  {
    "path": "SoA/TestUIScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestUIScreen.h\"\n\n#include <Vorb/ui/InputDispatcher.h>\n\n#include \"App.h\"\n#include \"InputMapper.h\"\n#include \"Inputs.h\"\n\nTestUIScreen::TestUIScreen(const App* app, CommonState* state) : IAppScreen<App>(app),\n    m_commonState(state)\n{\n    // Empty\n}\n\ni32 TestUIScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\ni32 TestUIScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestUIScreen::build() {\n    // Empty\n}\n\nvoid TestUIScreen::destroy(const vui::GameTime&) {\n    // Empty\n}\n\nvoid TestUIScreen::onEntry(const vui::GameTime&) {\n    vui::GameWindow* window = m_commonState->window;\n    m_viewport = vui::Viewport(window);\n\n    m_sb.init();\n    m_font.init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n\n    m_viewport.init(\"TestUIScreen\", { 0.0f, 0.0f, { vui::DimensionType::PIXEL, vui::DimensionType::PIXEL } }, { 1.0f, 1.0f, { vui::DimensionType::WINDOW_WIDTH_PERCENTAGE, vui::DimensionType::WINDOW_HEIGHT_PERCENTAGE } }, &m_font, &m_sb);\n\n    m_panels[0].init(\"panel1\", f32v4(0.0f));\n    m_panels[1].init(\"panel2\", f32v4(0.0f));\n    m_panels[2].init(\"panel3\", f32v4(0.0f));\n    m_panels[3].init(\"panel4\", f32v4(0.0f));\n    m_panels[4].init(\"panel5\", f32v4(0.0f));\n\n    m_panels[0].setColor(color4{ 255, 0, 0 });\n    m_panels[0].setHoverColor(color4{ 0, 255, 0 });\n    m_panels[1].setColor(color4{ 0, 0, 255 });\n    m_panels[1].setHoverColor(color4{ 255, 255, 0 });\n    m_panels[2].setColor(color4{ 255, 0, 255 });\n    m_panels[2].setHoverColor(color4{ 0, 255, 255 });\n    m_panels[3].setColor(color4{ 0, 0, 0 });\n    m_panels[3].setHoverColor(color4{ 255, 255, 255 });\n    m_panels[4].setColor(color4{ 123, 34, 235 });\n    m_panels[4].setHoverColor(color4{ 234, 100, 0 });\n\n    m_panels[0].setZIndex(1);\n    m_panels[1].setZIndex(2);\n    m_panels[2].setZIndex(3);\n    m_panels[3].setZIndex(4);\n    m_panels[4].setZIndex(5);\n\n    m_panels[0].setAutoScroll(true);\n    m_panels[1].setAutoScroll(true);\n    m_panels[2].setAutoScroll(true);\n    m_panels[3].setAutoScroll(true);\n    m_panels[4].setAutoScroll(true);\n\n    m_panels[0].setDockState(vui::DockState::BOTTOM);\n    m_panels[1].setDockState(vui::DockState::LEFT);\n    m_panels[2].setDockState(vui::DockState::LEFT);\n    m_panels[3].setDockState(vui::DockState::TOP);\n    m_panels[4].setDockState(vui::DockState::FILL);\n\n    m_panels[0].setRawDockSize({ 0.25f, { vui::DimensionType::VIEWPORT_HEIGHT_PERCENTAGE } });\n    m_panels[1].setRawDockSize({ 0.2f, { vui::DimensionType::VIEWPORT_WIDTH_PERCENTAGE } });\n    m_panels[2].setRawDockSize({ 0.2f, { vui::DimensionType::VIEWPORT_WIDTH_PERCENTAGE } });\n    m_panels[3].setRawDockSize({ 0.25f, { vui::DimensionType::VIEWPORT_HEIGHT_PERCENTAGE } });\n\n    m_checkBox.init(\"CheckBox\", f32v4(30.0f, 30.0f, 150.0f, 30.0f));\n    m_checkBox.setPadding(f32v4(10.0f, 5.0f, 10.0f, 5.0f));\n    m_checkBox.setText(\"Hello, World!\");\n    m_checkBox.setTextScale(f32v2(0.65f));\n    m_checkBox.setTextAlign(vg::TextAlign::CENTER);\n    m_checkBox.setClipping(vui::Clipping{ vui::ClippingState::HIDDEN, vui::ClippingState::HIDDEN, vui::ClippingState::HIDDEN, vui::ClippingState::HIDDEN });\n\n    m_panels[0].addWidget(&m_checkBox);\n\n    m_label.init(\"Label\", f32v4(130.0f, 130.0f, 120.0f, 30.0f));\n    m_label.setPadding(f32v4(10.0f, 5.0f, 10.0f, 5.0f));\n    m_label.setText(\"Wooooo!\");\n    m_label.setTextScale(f32v2(0.65f));\n    m_label.setTextAlign(vg::TextAlign::CENTER);\n\n    m_panels[1].addWidget(&m_label);\n\n    m_button.init(\"Button\", f32v4(60.0f, 130.0f, 120.0f, 30.0f));\n    m_button.setPadding(f32v4(10.0f, 5.0f, 10.0f, 5.0f));\n    m_button.setText(\"Click Me!\");\n    m_button.setTextScale(f32v2(0.65f));\n    m_button.setTextAlign(vg::TextAlign::CENTER);\n\n    m_panels[2].addWidget(&m_button);\n\n    m_comboBox.init(\"ComboBox\", f32v4(60.0f, 130.0f, 170.0f, 30.0f));\n\n    m_comboBox.addItem(\"This is One.\");\n    m_comboBox.addItem(\"This is Two.\");\n    m_comboBox.addItem(\"This is Three.\");\n    m_comboBox.addItem(\"This is Four.\");\n\n    // TODO(Matthew): Padding not supported by combobox yet, I think - too distracted to check, just occurred to me.\n    // m_comboBox.setPadding(f32v4(10.0f, 5.0f, 10.0f, 5.0f));\n    m_comboBox.setText(\"Click Me!\");\n    m_comboBox.setTextScale(f32v2(0.65f));\n    m_comboBox.setTextAlign(vg::TextAlign::CENTER);\n    m_comboBox.setBackColor(color::Aquamarine);\n    m_comboBox.setBackHoverColor(color::Azure);\n    m_comboBox.setZIndex(2);\n\n    m_comboBox.setMaxDropHeight(90.0f);\n\n    m_comboBox.selectItem(0);\n\n    m_panels[4].addWidget(&m_comboBox);\n\n    m_widgetList.init(\"WidgetList\", f32v4(50.0f, 50.0f, 200.0f, 200.0f));\n    m_widgetList.setBackColor(color::Bisque);\n    m_widgetList.setBackHoverColor(color::Crimson);\n    m_widgetList.setAutoScroll(true);\n    m_widgetList.setSpacing(0.0f);\n    m_widgetList.setMaxHeight(200.0f);\n\n    size_t i = 0;\n    for (auto& button : m_listButtons) {\n        button.init(\"ListButton\" + std::to_string(i++), f32v4(0.0f, 0.0f, 200.0f, 50.0f));\n        button.setBackColor(color4(40.0f * (f32)i, 20.0f, 20.0f));\n        button.setBackHoverColor(color4(20.0f, 40.0f * (f32)i, 20.0f));\n        button.setText(\"ListButton\" + std::to_string(i));\n        button.setTextScale(f32v2(0.65f));\n        button.setTextAlign(vg::TextAlign::CENTER);\n\n        m_widgetList.addItem(&button);\n    }\n\n    m_panels[3].addWidget(&m_widgetList);\n\n    m_viewport.addWidget(&m_panels[0]);\n    m_viewport.addWidget(&m_panels[1]);\n    m_viewport.addWidget(&m_panels[2]);\n    m_viewport.addWidget(&m_panels[3]);\n    m_viewport.addWidget(&m_panels[4]);\n\n    m_viewport.enable();\n}\n\nvoid TestUIScreen::onExit(const vui::GameTime&) {\n    m_viewport.dispose();\n}\n\nvoid TestUIScreen::update(const vui::GameTime&) {\n    m_viewport.update();\n}\n\nvoid TestUIScreen::draw(const vui::GameTime&) {\n    glClear(GL_COLOR_BUFFER_BIT);\n\n    m_viewport.draw();\n}\n"
  },
  {
    "path": "SoA/TestUIScreen.h",
    "content": "#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/ui/widgets/Button.h>\n#include <Vorb/ui/widgets/CheckBox.h>\n#include <Vorb/ui/widgets/ComboBox.h>\n#include <Vorb/ui/widgets/Label.h>\n#include <Vorb/ui/widgets/Panel.h>\n#include <Vorb/ui/widgets/Viewport.h>\n#include <Vorb/ui/widgets/WidgetList.h>\n\n#include \"CommonState.h\"\n\nclass InputMapper;\n\nclass TestUIScreen : public vui::IAppScreen<App> {\npublic:\n    TestUIScreen(const App* app, CommonState* state);\n\n    i32 getNextScreen() const override;\n    i32 getPreviousScreen() const override;\n\n    void build() override;\n    void destroy(const vui::GameTime&) override;\n\n    void onEntry(const vui::GameTime&) override;\n    void onExit(const vui::GameTime&) override;\n\n    void update(const vui::GameTime&) override;\n    void draw(const vui::GameTime&) override;\nprivate:\n    CommonState* m_commonState;\n\n    vg::SpriteBatch m_sb;\n    vg::SpriteFont  m_font;\n\n    vui::Viewport   m_viewport;\n    vui::Panel      m_panels[5];\n    vui::CheckBox   m_checkBox;\n    vui::Label      m_label;\n    vui::Button     m_button;\n    vui::ComboBox   m_comboBox;\n    vui::WidgetList m_widgetList;\n    vui::Button     m_listButtons[6];\n};\n"
  },
  {
    "path": "SoA/TestVoxelModelScreen.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TestVoxelModelScreen.h\"\n\n\n#include <Vorb/colors.h>\n#include <Vorb/graphics/GLStates.h>\n#include <Vorb/ui/InputDispatcher.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/Timing.h>\n\n#include \"DebugRenderer.h\"\n#include \"Errors.h\"\n#include \"ModelMesher.h\"\n#include \"VoxelModelLoader.h\"\n#include \"soaUtils.h\"\n\nTestVoxelModelScreen::TestVoxelModelScreen(const App* app) :\nIAppScreen<App>(app) {\n  // Empty\n}\n\ni32 TestVoxelModelScreen::getNextScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\ni32 TestVoxelModelScreen::getPreviousScreen() const {\n    return SCREEN_INDEX_NO_SCREEN;\n}\n\nvoid TestVoxelModelScreen::build() {\n    // Empty\n}\nvoid TestVoxelModelScreen::destroy(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestVoxelModelScreen::onEntry(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        if(e.keyCode==VKEY_ESCAPE)\n        {\n            exit(0);\n        }\n    });\n\n    m_sb.init();\n    m_sf.init(\"Fonts/orbitron_bold-webfont.ttf\", 32);\n  \n    m_camera.init(m_game->getWindow().getAspectRatio());\n    m_camera.setPosition(f64v3(0, 0, 100));\n    m_camera.setClippingPlane(0.01f, 100000.0f);\n    m_camera.setDirection(f32v3(0.0f, 0.0f, -1.0f));\n    m_camera.setRight(f32v3(1.0f, 0.0f, 0.0f));\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onMotion, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseMotionEvent& e) {\n        if (m_mouseButtons[0]) {\n            m_camera.rotateFromMouse(-e.dx, -e.dy, 0.1f);\n        }\n        if (m_mouseButtons[1]) {\n            m_camera.rollFromMouse((f32)e.dx, 0.1f);\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::LEFT) m_mouseButtons[0] = true;\n        if (e.button == vui::MouseButton::RIGHT) m_mouseButtons[1] = true;\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::mouse.onButtonUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::MouseButtonEvent& e) {\n        if (e.button == vui::MouseButton::LEFT) m_mouseButtons[0] = false;\n        if (e.button == vui::MouseButton::RIGHT) m_mouseButtons[1] = false;\n    });\n\n    m_movingForward = false;\n    m_movingBack = false;\n    m_movingLeft = false;\n    m_movingRight = false;\n    m_movingUp = false;\n    m_movingDown = false;\n\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyDown, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        switch(e.keyCode) {\n        case VKEY_W:\n            m_movingForward = true;\n            break;\n        case VKEY_S:\n            m_movingBack = true;\n            break;\n        case VKEY_A:\n            m_movingLeft = true;\n            break;\n        case VKEY_D:\n            m_movingRight = true;\n            break;\n        case VKEY_SPACE:\n            m_movingUp = true;\n            break;\n        case VKEY_LSHIFT:\n            m_movingFast = true;\n            break;\n        case VKEY_M:\n            m_wireFrame = !m_wireFrame;\n            break;\n        case VKEY_LEFT:\n            if (m_currentMesh == 0) {\n                m_currentMesh = m_meshes.size() - 1;\n            } else {\n                m_currentMesh--;\n            }\n            break;\n        case VKEY_RIGHT:\n            m_currentMesh++;\n            if (m_currentMesh >= m_meshes.size()) m_currentMesh = 0;\n            break;\n        case VKEY_F1:\n            // Reload shader\n            m_renderer.dispose();\n            m_renderer.initGL();\n            break;\n        }\n    });\n    m_hooks.addAutoHook(vui::InputDispatcher::key.onKeyUp, [&](Sender s VORB_MAYBE_UNUSED, const vui::KeyEvent& e) {\n        switch(e.keyCode) {\n        case VKEY_W:\n            m_movingForward = false;\n            break;\n        case VKEY_S:\n            m_movingBack = false;\n            break;\n        case VKEY_A:\n            m_movingLeft = false;\n            break;\n        case VKEY_D:\n            m_movingRight = false;\n            break;\n        case VKEY_SPACE:\n            m_movingUp = false;\n            break;\n        case VKEY_LSHIFT:\n            m_movingFast = false;\n            break;\n        }\n    });\n\n\n    m_currentMesh = 0;\n\n    /************************************************************************/\n    /* Mesh Creation                                                        */\n    /************************************************************************/\n    { // Female model\n        nString path = \"Models/human_female.qb\";\n        VoxelModel* model = new VoxelModel();\n        model->loadFromFile(path);\n        \n        addMesh(path, VoxelMeshType::BASIC, model);\n        addMesh(path, VoxelMeshType::MARCHING_CUBES, model);\n        // You can add DUAL_COUNTOURING too, but beware: The implementation is very slow.\n        // addMesh(\"Models/human_female.qb\", VoxelMeshType::DUAL_CONTOURING, model);\n    }\n\n    { // Male model\n        nString path = \"Models/human_male.qb\";\n        VoxelModel* model = new VoxelModel;\n        model->loadFromFile(path);\n        \n        addMesh(path, VoxelMeshType::BASIC, model);\n        addMesh(path, VoxelMeshType::MARCHING_CUBES, model);\n        // You can add DUAL_COUNTOURING too, but beware: The implementation is very slow.\n        // addMesh(\"Models/human_female.qb\", VoxelMeshType::DUAL_CONTOURING, model);\n    }\n    /************************************************************************/\n    /*                                                                      */\n    /************************************************************************/\n\n    // init GL\n    m_renderer.initGL();\n\n    m_mouseButtons[0] = false;\n    m_mouseButtons[1] = false;\n    m_mouseButtons[2] = false;\n\n    // Set clear state\n    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);\n    glClearDepth(1.0);\n\n}\nvoid TestVoxelModelScreen::onExit(const vui::GameTime& gameTime VORB_UNUSED) {\n    // Empty\n}\n\nvoid TestVoxelModelScreen::update(const vui::GameTime& gameTime) {\n    f32 speed = 5.0f;\n    if (m_movingFast) speed *= 5.0f;\n    if(m_movingForward) {\n        f32v3 offset = m_camera.getDirection() * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if(m_movingBack) {\n        f32v3 offset = m_camera.getDirection() * -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if(m_movingLeft) {\n        f32v3 offset = m_camera.getRight() * -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if(m_movingRight) {\n        f32v3 offset = m_camera.getRight() * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if(m_movingUp) {\n        f32v3 offset = f32v3(0, 1, 0) * speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    if(m_movingDown) {\n        f32v3 offset = f32v3(0, 1, 0) *  -speed * (f32)gameTime.elapsed;\n        m_camera.offsetPosition(offset);\n    }\n    m_camera.update();\n}\nvoid TestVoxelModelScreen::draw(const vui::GameTime& gameTime VORB_MAYBE_UNUSED) {\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n    vg::DepthState::FULL.set();\n\n    // The winding is backwards for some reason on dual contouring...\n    if (m_meshInfos[m_currentMesh].meshType == VoxelMeshType::DUAL_CONTOURING) {\n        vg::RasterizerState::CULL_COUNTER_CLOCKWISE.set();\n    } else {\n        vg::RasterizerState::CULL_CLOCKWISE.set();\n    }\n\n    // Draw the mesh\n    if (m_wireFrame) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n    m_renderer.draw(&m_meshes[m_currentMesh], m_camera.getViewProjectionMatrix(), m_camera.getPosition(), f64q());\n    if (m_wireFrame) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\n    m_sb.begin();\n    char buf[512];\n    // Get a string name\n    nString typeString = \"UNKNOWN\";\n    switch (m_meshInfos[m_currentMesh].meshType) {\n        case VoxelMeshType::BASIC:\n            typeString = \"Basic\";\n            break;\n        case VoxelMeshType::MARCHING_CUBES:\n            typeString = \"Marching Cubes\";\n            break;\n        case VoxelMeshType::DUAL_CONTOURING:\n            typeString = \"Dual Contouring\";\n            break;\n    }\n\n    // Build the string to draw\n    sprintf(buf, \"Name: %s\\nType: %s\\nTriangles: %d\\nBuild Time: %.4lf ms\\nsize: %f mb\",\n            m_meshInfos[m_currentMesh].name.c_str(),\n            typeString.c_str(),\n            m_meshInfos[m_currentMesh].numPolygons,\n            m_meshInfos[m_currentMesh].buildTime,\n            m_meshInfos[m_currentMesh].size / 1000.0f / 1000.0f);\n\n    // Draw the string\n    m_sb.drawString(&m_sf, buf, f32v2(30.0f), f32v2(1.0f), color::White);\n\n    // Flush to screen\n    m_sb.end();\n    m_sb.render(f32v2(m_game->getWindow().getViewportDims()));\n\n    checkGlError(\"TestVoxelModelScreen::draw\");\n}\n\nvoid TestVoxelModelScreen::addMesh(const nString& name, VoxelMeshType meshType, VoxelModel* model) {\n    MeshDebugInfo info;\n    info.name = name;\n    info.meshType = meshType;\n    info.model = model;\n    info.size = model->getMatrix().size.x * model->getMatrix().size.y * model->getMatrix().size.z * sizeof(color4);\n    PreciseTimer timer;\n    timer.start();\n    // TODO(Ben): Move the switch inside ModelMesher\n    switch (meshType) {\n        case VoxelMeshType::BASIC:\n            m_meshes.push_back(ModelMesher::createMesh(model));\n            break;\n        case VoxelMeshType::MARCHING_CUBES:\n            m_meshes.push_back(ModelMesher::createMarchingCubesMesh(model));\n            break;\n        case VoxelMeshType::DUAL_CONTOURING:\n            m_meshes.push_back(ModelMesher::createDualContouringMesh(model));\n            break;\n    }\n    info.buildTime = timer.stop();\n    info.numPolygons = m_meshes.back().getTriCount();\n    m_meshInfos.push_back(info);\n}"
  },
  {
    "path": "SoA/TestVoxelModelScreen.h",
    "content": "///\n/// TestBlockViewScreen.h\n/// Seed of Andromeda\n///\n/// Created by Frank McCoy on 7 April 2015\n/// Copyright 2014-2015 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Load and display a voxel model in .QB file format\n///\n\n#pragma once\n\n#ifndef TestVoxelModelScreen_h__\n#define TestVoxelModelScreen_h__\n\n#include <vector>\n\n#include <Vorb/Event.hpp>\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/ui/IGameScreen.h>\n#include <Vorb/graphics/SpriteBatch.h>\n#include <Vorb/graphics/SpriteFont.h>\n\n#include \"Camera.h\"\n#include \"VoxelModel.h\"\n#include \"VoxelModelRenderer.h\"\n\nclass App;\nclass VoxelMatrix;\nclass VoxelModelVertex;\n\nenum class VoxelMeshType { BASIC, MARCHING_CUBES, DUAL_CONTOURING };\n\nstruct MeshDebugInfo {\n    nString name;\n    VoxelMeshType meshType;\n    VoxelModel* model;\n    ui32 numPolygons;\n    f64 buildTime;\n    f32 size;\n};\n\nclass TestVoxelModelScreen : public vui::IAppScreen<App> {\npublic:\n    TestVoxelModelScreen(const App* app);\n    /************************************************************************/\n    /* IGameScreen functionality                                            */\n    /************************************************************************/\n    virtual i32 getNextScreen() const override;\n    virtual i32 getPreviousScreen() const override;\n    virtual void build() override;\n    virtual void destroy(const vui::GameTime& gameTime) override;\n    virtual void onEntry(const vui::GameTime& gameTime) override;\n    virtual void onExit(const vui::GameTime& gameTime) override;\n    virtual void update(const vui::GameTime& gameTime) override;\n    virtual void draw(const vui::GameTime& gameTime) override;\nprivate:\n    void addMesh(const nString& name, VoxelMeshType meshType, VoxelModel* model);\n    Camera m_camera;\n    AutoDelegatePool m_hooks; ///< Input hooks reservoir\n    bool m_mouseButtons[3];\n\n    ui32 m_currentMesh = 0;\n    std::vector<VoxelModelMesh> m_meshes;\n    std::vector<MeshDebugInfo> m_meshInfos;\n    VoxelModelRenderer m_renderer;\n    bool m_wireFrame = false;\n\n    vg::SpriteBatch m_sb;\n    vg::SpriteFont m_sf;\n\n    bool m_movingForward;\n    bool m_movingBack;\n    bool m_movingLeft;\n    bool m_movingRight;\n    bool m_movingUp;\n    bool m_movingDown;\n    bool m_movingFast;\n};\n\n#endif"
  },
  {
    "path": "SoA/Thread.h",
    "content": "#pragma once\n#include <thread>\n\ntemplate<typename T>\nclass Thread {\npublic:\n    Thread(i32(*func)(T)) :\n        _func(func),\n        _isFinished(false),\n        _exitCode(0),\n        _argCopy({}) {\n        _threadFunction = [] (Thread<T>* thread) {\n            thread->_exitCode = (*thread->_func)(thread->_argCopy);\n            thread->_isFinished = true;\n        };\n    }\n    Thread() : Thread(nullptr) {}\n\n    void start(const T& arg) {\n        _argCopy = arg;\n        _thread = std::thread(_threadFunction, this);\n    }\n    void setFunction(i32(*func)(T)) {\n        _func = func;\n    }\n\n    const bool getIsFinished() const {\n        return _isFinished;\n    }\n    const i32 getErrorCode() const {\n        return _exitCode;\n    }\nprivate:\n    void(*_threadFunction)(Thread<T>*);\n    i32(*_func)(T);\n    std::thread _thread;\n\n    T _argCopy;\n    bool _isFinished;\n    i32 _exitCode;\n};\n\ntypedef i32(*ThreadVoidFunction)();\n\nclass ThreadVoid {\npublic:\n    ThreadVoid(ThreadVoidFunction func) :\n        _func(func),\n        _isFinished(false),\n        _exitCode(0) {\n        _threadFunction = [] (ThreadVoid* thread) {\n            thread->_exitCode = thread->_func();\n            thread->_isFinished = true;\n        };\n    }\n    ThreadVoid() : ThreadVoid(nullptr) {}\n\n    void start() {\n        _thread = std::thread(_threadFunction, this);\n    }\n    void setFunction(ThreadVoidFunction func) {\n        _func = func;\n    }\n\n    const bool getIsFinished() const {\n        return _isFinished;\n    }\n    const i32 getErrorCode() const {\n        return _exitCode;\n    }\nprivate:\n    void(*_threadFunction)(ThreadVoid*);\n    ThreadVoidFunction _func;\n    std::thread _thread;\n\n    bool _isFinished;\n    i32 _exitCode;\n};"
  },
  {
    "path": "SoA/TransparentVoxelRenderStage.cpp",
    "content": "#include \"stdafx.h\"\n#include \"TransparentVoxelRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n#include \"BlockPack.h\"\n#include \"BlockTexturePack.h\"\n#include \"Camera.h\"\n#include \"ChunkMeshManager.h\"\n#include \"ChunkRenderer.h\"\n#include \"GameRenderParams.h\"\n#include \"GeometrySorter.h\"\n#include \"Chunk.h\"\n#include \"RenderUtils.h\"\n#include \"ShaderLoader.h\"\n#include \"SoaOptions.h\"\n\nvoid TransparentVoxelRenderStage::hook(ChunkRenderer* renderer, const GameRenderParams* gameRenderParams) {\n    m_renderer = renderer;\n    m_gameRenderParams = gameRenderParams;\n}\n\nvoid TransparentVoxelRenderStage::render(const Camera* camera VORB_MAYBE_UNUSED) {\n    glDepthMask(GL_FALSE);\n    ChunkMeshManager* cmm = m_gameRenderParams->chunkMeshmanager;\n\n    const f64v3& position = m_gameRenderParams->chunkCamera->getPosition();\n\n    m_renderer->beginTransparent(m_gameRenderParams->blockTexturePack->getAtlasTexture(), m_gameRenderParams->sunlightDirection,\n                                 m_gameRenderParams->sunlightColor);\n\n    glDisable(GL_CULL_FACE);\n\n    // f64v3 cpos;\n\n    static i32v3 oldPos = i32v3(0);\n    bool sort = false;\n\n    i32v3 intPosition(fastFloor(position.x), fastFloor(position.y), fastFloor(position.z));\n\n    if (oldPos != intPosition) {\n        //sort the geometry\n        sort = true;\n        oldPos = intPosition;\n    }\n    const std::vector <ChunkMesh *>& chunkMeshes = cmm->getChunkMeshes();\n    {\n        std::lock_guard<std::mutex> l(cmm->lckActiveChunkMeshes);\n        if (chunkMeshes.empty()) return;\n        for (size_t i = 0; i < chunkMeshes.size(); i++) {\n            ChunkMesh* cm = chunkMeshes[i];\n            if (sort) cm->needsSort = true;\n\n            if (cm->inFrustum) {\n                // TODO(Ben): We should probably do this outside of a lock\n                if (cm->needsSort) {\n                    cm->needsSort = false;\n                    if (cm->transQuadIndices.size() != 0) {\n                        GeometrySorter::sortTransparentBlocks(cm, intPosition);\n\n                        //update index data buffer\n                        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cm->transIndexID);\n                        glBufferData(GL_ELEMENT_ARRAY_BUFFER, cm->transQuadIndices.size() * sizeof(ui32), NULL, GL_STATIC_DRAW);\n                        void* v = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, cm->transQuadIndices.size() * sizeof(ui32), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);\n\n                        if (v == NULL) pError(\"Failed to map sorted transparency buffer.\");\n                        memcpy(v, &(cm->transQuadIndices[0]), cm->transQuadIndices.size() * sizeof(ui32));\n                        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n                    }\n                }\n\n                m_renderer->drawTransparent(cm, position,\n                                            m_gameRenderParams->chunkCamera->getViewProjectionMatrix());\n            }\n        }\n    }\n    glEnable(GL_CULL_FACE);\n\n    m_renderer->end();\n    glDepthMask(GL_TRUE);\n}\n\n"
  },
  {
    "path": "SoA/TransparentVoxelRenderStage.h",
    "content": "/// \n///  TransparentVoxelRenderStage.h\n///  Seed of Andromeda\n///\n///  Created by Benjamin Arnold on 1 Nov 2014\n///  Copyright 2014 Regrowth Studios\n///  MIT License\n///  \n///  This file provides the implementation of the transparent voxel\n///  render stage. Transparent voxels have partial transparency, and\n///  will be sorted and blended.\n///\n\n#pragma once\n\n#ifndef TransparentVoxelRenderStage_h__\n#define TransparentVoxelRenderStage_h__\n\n#include \"IRenderStage.h\"\n\n#include <Vorb/graphics/GLProgram.h>\n\nclass Camera;\nclass ChunkRenderer;\nclass GameRenderParams;\nclass MeshManager;\n\nclass TransparentVoxelRenderStage : public IRenderStage {\npublic:\n    void hook(ChunkRenderer* renderer, const GameRenderParams* gameRenderParams);\n\n    /// Draws the render stage\n    virtual void render(const Camera* camera) override;\nprivate:\n    ChunkRenderer* m_renderer;\n    const GameRenderParams* m_gameRenderParams = nullptr; ///< Handle to some shared parameters\n};\n\n#endif // TransparentVoxelRenderStage_h__\n\n"
  },
  {
    "path": "SoA/VRayHelper.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VRayHelper.h\"\n\n#include \"BlockPack.h\"\n#include \"ChunkGrid.h\"\n#include \"VoxelRay.h\"\n#include \"VoxelSpaceConversions.h\"\n\nbool solidVoxelPredBlock(const Block& block) {\n    return block.collide == true;\n}\n\nconst VoxelRayQuery VRayHelper::getQuery(const f64v3& pos, const f32v3& dir, f64 maxDistance, ChunkGrid& cg, PredBlock f) {\n\n    // Set the ray coordinates\n    VoxelRay vr(pos, f64v3(dir));\n\n    // Create The Query At The Current Position\n    VoxelRayQuery query = {};\n    \n    query.location = vr.getNextVoxelPosition();\n    query.distance = vr.getDistanceTraversed();\n\n    // A minimum chunk position for determining voxel coords using only positive numbers\n    i32v3 relativeChunkSpot = VoxelSpaceConversions::voxelToChunk(f64v3(pos.x - maxDistance, pos.y - maxDistance, pos.z - maxDistance)) * CHUNK_WIDTH;\n    i32v3 relativeLocation;\n\n    // Chunk position\n    i32v3 chunkPos;\n\n    // TODO: Use A Bounding Box Intersection First And Allow Traversal Beginning Outside The Voxel World\n\n    // Keep track of the previous chunk for locking\n    ChunkHandle chunk;\n    query.chunkID = ChunkID(0xffffffffffffffff);\n    bool locked = false;\n\n    // Loop Traversal\n    while (query.distance < maxDistance) {\n       \n        chunkPos = VoxelSpaceConversions::voxelToChunk(query.location);\n\n        relativeLocation = query.location - relativeChunkSpot;\n        ChunkID id(chunkPos);\n        if (id != query.chunkID) {\n            query.chunkID = id;\n            if (chunk.isAquired()) {\n                if (locked) {\n                    chunk->dataMutex.unlock();\n                    locked = false;\n                }\n                chunk.release();\n            }\n            chunk = cg.accessor.acquire(id);\n            if (chunk->isAccessible) {\n                chunk->dataMutex.lock();\n                locked = true;\n            }\n        }\n        \n        if (locked) {\n            // Calculate Voxel Index\n            query.voxelIndex =\n                (relativeLocation.x & 0x1f) +\n                (relativeLocation.y & 0x1f) * CHUNK_LAYER +\n                (relativeLocation.z & 0x1f) * CHUNK_WIDTH;\n\n            // Get Block ID\n            query.id = chunk->blocks.get(query.voxelIndex);\n\n            // Check For The Block ID\n            if (f(cg.blockPack->operator[](query.id))) {\n                if (locked) chunk->dataMutex.unlock();\n                chunk.release();\n                return query;\n            }\n        }\n        \n        // Traverse To The Next\n        query.location = vr.getNextVoxelPosition();\n        query.distance = vr.getDistanceTraversed();\n    }\n    if (chunk.isAquired()) {\n        if (locked) chunk->dataMutex.unlock();\n        chunk.release();\n    }\n    return query;\n}\nconst VoxelRayFullQuery VRayHelper::getFullQuery(const f64v3& pos, const f32v3& dir, f64 maxDistance, ChunkGrid& cg, PredBlock f) {\n    // First Convert To Voxel Coordinates\n    VoxelRay vr(pos, f64v3(dir));\n\n    // Create The Query At The Current Position\n    VoxelRayFullQuery query = {};\n    query.inner.location = vr.getNextVoxelPosition();\n    query.inner.distance = vr.getDistanceTraversed();\n    query.outer.location = query.inner.location;\n    query.outer.distance = query.inner.distance;\n\n    // A minimum chunk position for determining voxel coords using only positive numbers\n    i32v3 relativeChunkSpot = VoxelSpaceConversions::voxelToChunk(f64v3(pos.x - maxDistance, pos.y - maxDistance, pos.z - maxDistance)) * CHUNK_WIDTH;\n    i32v3 relativeLocation;\n\n    i32v3 chunkPos;\n\n    // TODO: Use A Bounding Box Intersection First And Allow Traversal Beginning Outside The Voxel World\n\n    // Keep track of the previous chunk for locking\n    ChunkHandle chunk;\n    query.inner.chunkID = ChunkID(0xffffffffffffffff);\n    bool locked = false;\n\n    // Loop Traversal\n    while (query.inner.distance < maxDistance) {\n\n        chunkPos = VoxelSpaceConversions::voxelToChunk(query.inner.location);\n        ChunkID id(chunkPos);\n       \n        if (id != query.inner.chunkID) {\n            query.inner.chunkID = id;\n            if (chunk.isAquired()) {\n                if (locked) {\n                    chunk->dataMutex.unlock();\n                    locked = false;\n                }\n                chunk.release();\n            }\n            chunk = cg.accessor.acquire(id);\n            if (chunk->isAccessible) {\n                chunk->dataMutex.lock();\n                locked = true;\n            }\n        }\n       \n        if (locked) {\n            relativeLocation = query.inner.location - relativeChunkSpot;\n            // Calculate Voxel Index\n            query.inner.voxelIndex =\n                (relativeLocation.x & 0x1f) +\n                (relativeLocation.y & 0x1f) * CHUNK_LAYER +\n                (relativeLocation.z & 0x1f) * CHUNK_WIDTH;\n\n            // Get Block ID\n            query.inner.id = chunk->blocks.get(query.inner.voxelIndex);\n\n            // Check For The Block ID\n            if (f(cg.blockPack->operator[](query.inner.id))) {\n                if (locked) chunk->dataMutex.unlock();\n                chunk.release();\n                return query;\n            }\n\n            // Refresh Previous Query\n            query.outer = query.inner;\n        }\n       \n        // Traverse To The Next\n        query.inner.location = vr.getNextVoxelPosition();\n        query.inner.distance = vr.getDistanceTraversed();\n    }\n    if (chunk.isAquired()) {\n        if (locked) chunk->dataMutex.unlock();\n        chunk.release();\n    }\n    return query;\n}\n\n"
  },
  {
    "path": "SoA/VRayHelper.h",
    "content": "#pragma once\nclass ChunkGrid;\nclass Chunk;\n\n#include \"BlockData.h\"\n\n// Returns True For Certain Block Type\ntypedef bool(*PredBlock)(const Block& block);\n\nextern bool solidVoxelPredBlock(const Block& block);\n\n// Queryable Information\nclass VoxelRayQuery {\npublic:\n    // Block ID\n    BlockID id;\n\n    // Location Of The Picked Block\n    i32v3 location;\n    f64 distance;\n\n    // Address Information\n    ChunkID chunkID;\n    ui16 voxelIndex;\n};\nclass VoxelRayFullQuery {\npublic:\n    // The Place Of The Chosen Block\n    VoxelRayQuery inner;\n\n    // The Place Before The Chosen Block\n    VoxelRayQuery outer;\n};\n\n// Utility Methods For Using A Voxel Ray\nclass VRayHelper {\npublic:\n    // Resolve A Simple Voxel Query\n    static const VoxelRayQuery getQuery(const f64v3& pos, const f32v3& dir, f64 maxDistance, ChunkGrid& cm, PredBlock f = &solidVoxelPredBlock);\n\n    // Resolve A Voxel Query Keeping Previous Query Information\n    static const VoxelRayFullQuery getFullQuery(const f64v3& pos, const f32v3& dir, f64 maxDistance, ChunkGrid& cm, PredBlock f = &solidVoxelPredBlock);\n};"
  },
  {
    "path": "SoA/Vertex.h",
    "content": "///\n/// Vertex.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 21 Jun 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Vertex definitions for SoA\n///\n\n#pragma once\n\n#ifndef Vertex_h__\n#define Vertex_h__\n\n#include \"Vorb/types.h\"\n\nclass ColorVertex {\npublic:\n    f32v3 position;\n    ubyte color[4];\n};\n\nconst ui8 MESH_FLAG_ACTIVE = 0x1;\nconst ui8 MESH_FLAG_MERGE_RIGHT = 0x2;\nconst ui8 MESH_FLAG_MERGE_FRONT = 0x4;\n\n// Describes atlas positioning for a BlockVertex\nstruct AtlasTexturePosition {\n    struct {\n        ui8 atlas;\n        ui8 index;\n    } base;\n    struct {\n        ui8 atlas;\n        ui8 index;\n    } overlay;\n\n    bool operator==(const AtlasTexturePosition& rhs) const {\n        // Assumes 32 bit struct.\n        return *((const ui32*)this) == *((const ui32*)&rhs);\n    }\n};\nstatic_assert(sizeof(AtlasTexturePosition) == sizeof(ui32), \"AtlasTexturePosition compare will fail.\");\n\n// Size: 32 Bytes\nstruct BlockVertex {\n\n    BlockVertex() {}\n    //need deconstructor because of the non-trivial union\n    ~BlockVertex() { position.ui8v3::~ui8v3(); }\n\n    union {\n        struct {\n            ui8 x;\n            ui8 y;\n            ui8 z;\n        };\n        ui8v3 position;\n    };\n    ui8 face;\n\n    ui8v2 tex;\n    ui8 animationLength;\n    ui8 blendMode;\n\n    AtlasTexturePosition texturePosition;\n    AtlasTexturePosition normTexturePosition;\n    AtlasTexturePosition dispTexturePosition;\n    \n    ui8v2 textureDims;\n    ui8v2 overlayTextureDims;\n\n    color3 color;\n    ui8 mesherFlags;\n\n    color3 overlayColor;\n    ui8 padding;\n\n    // This isn't a full comparison. Its just for greedy mesh comparison so its lightweight.\n    bool operator==(const BlockVertex& rhs) const {\n        return (color == rhs.color && overlayColor == rhs.overlayColor &&\n                texturePosition == rhs.texturePosition);\n    }\n};\nstatic_assert(sizeof(BlockVertex) == 32, \"Size of BlockVertex is not 32\");\n\nclass LiquidVertex {\npublic:\n    // TODO: x and z can be bytes?\n    f32v3 position; //12\n    ui8 tex[2]; //14\n    ui8 textureUnit; //15 \n    ui8 textureIndex; //16\n    ColorRGBA8 color; //20\n    ColorRGB8 lampColor; //23\n    ui8 sunlight; //24\n};\n\nclass PhysicsBlockVertex {\npublic:\n    ui8 position[3]; //3\n    ui8 blendMode; //4\n    ui8 tex[2]; //6\n    ui8 pad1[2]; //8\n\n    ui8 textureAtlas; //9\n    ui8 overlayTextureAtlas; //10\n    ui8 textureIndex; //11\n    ui8 overlayTextureIndex; //12\n\n    ui8 textureWidth; //13\n    ui8 textureHeight; //14\n    ui8 overlayTextureWidth; //15\n    ui8 overlayTextureHeight; //16\n\n    i8 normal[3]; //19\n    i8 pad2; //20\n};\n\n#endif // Vertex_h__\n"
  },
  {
    "path": "SoA/VirtualKeyKegDef.inl",
    "content": "KEG_ENUM_DECL(VirtualKey); \nKEG_ENUM_DEF(VirtualKey, VirtualKey, kt) {\n    using namespace keg;\n    kt.addValue(\"unknown\", VKEY_UNKNOWN);\n    kt.addValue(\"a\", VKEY_A);\n    kt.addValue(\"b\", VKEY_B);\n    kt.addValue(\"c\", VKEY_C);\n    kt.addValue(\"d\", VKEY_D);\n    kt.addValue(\"e\", VKEY_E);\n    kt.addValue(\"f\", VKEY_F);\n    kt.addValue(\"g\", VKEY_G);\n    kt.addValue(\"h\", VKEY_H);\n    kt.addValue(\"i\", VKEY_I);\n    kt.addValue(\"j\", VKEY_J);\n    kt.addValue(\"k\", VKEY_K);\n    kt.addValue(\"l\", VKEY_L);\n    kt.addValue(\"m\", VKEY_M);\n    kt.addValue(\"n\", VKEY_N);\n    kt.addValue(\"o\", VKEY_O);\n    kt.addValue(\"p\", VKEY_P);\n    kt.addValue(\"q\", VKEY_Q);\n    kt.addValue(\"r\", VKEY_R);\n    kt.addValue(\"s\", VKEY_S);\n    kt.addValue(\"t\", VKEY_T);\n    kt.addValue(\"u\", VKEY_U);\n    kt.addValue(\"v\", VKEY_V);\n    kt.addValue(\"w\", VKEY_W);\n    kt.addValue(\"x\", VKEY_X);\n    kt.addValue(\"y\", VKEY_Y);\n    kt.addValue(\"z\", VKEY_Z);\n    kt.addValue(\"1\", VKEY_1);\n    kt.addValue(\"2\", VKEY_2);\n    kt.addValue(\"3\", VKEY_3);\n    kt.addValue(\"4\", VKEY_4);\n    kt.addValue(\"5\", VKEY_5);\n    kt.addValue(\"6\", VKEY_6);\n    kt.addValue(\"7\", VKEY_7);\n    kt.addValue(\"8\", VKEY_8);\n    kt.addValue(\"9\", VKEY_9);\n    kt.addValue(\"0\", VKEY_0);\n    kt.addValue(\"return\", VKEY_RETURN);\n    kt.addValue(\"escape\", VKEY_ESCAPE);\n    kt.addValue(\"backspace\", VKEY_BACKSPACE);\n    kt.addValue(\"tab\", VKEY_TAB);\n    kt.addValue(\"space\", VKEY_SPACE);\n    kt.addValue(\"-\", VKEY_MINUS);\n    kt.addValue(\"=\", VKEY_EQUALS);\n    kt.addValue(\"[\", VKEY_LEFTBRACKET);\n    kt.addValue(\"]\", VKEY_RIGHTBRACKET);\n    kt.addValue(\"\\\\\", VKEY_BACKSLASH);\n    kt.addValue(\"?\", VKEY_NONUSHASH);\n    kt.addValue(\";\", VKEY_SEMICOLON);\n    kt.addValue(\"'\", VKEY_APOSTROPHE);\n    kt.addValue(\"`\", VKEY_GRAVE);\n    kt.addValue(\",\", VKEY_COMMA);\n    kt.addValue(\".\", VKEY_PERIOD);\n    kt.addValue(\"/\", VKEY_SLASH);\n    kt.addValue(\"caps_lock\", VKEY_CAPSLOCK);\n    kt.addValue(\"f1\", VKEY_F1);\n    kt.addValue(\"f2\", VKEY_F2);\n    kt.addValue(\"f3\", VKEY_F3);\n    kt.addValue(\"f4\", VKEY_F4);\n    kt.addValue(\"f5\", VKEY_F5);\n    kt.addValue(\"f6\", VKEY_F6);\n    kt.addValue(\"f7\", VKEY_F7);\n    kt.addValue(\"f8\", VKEY_F8);\n    kt.addValue(\"f9\", VKEY_F9);\n    kt.addValue(\"f10\", VKEY_F10);\n    kt.addValue(\"f11\", VKEY_F11);\n    kt.addValue(\"f12\", VKEY_F12);\n    kt.addValue(\"print_screen\", VKEY_PRINTSCREEN);\n    kt.addValue(\"scroll_lock\", VKEY_SCROLLLOCK);\n    kt.addValue(\"pause\", VKEY_PAUSE);\n    kt.addValue(\"insert\", VKEY_INSERT);\n    kt.addValue(\"home\", VKEY_HOME);\n    kt.addValue(\"page_up\", VKEY_PAGEUP);\n    kt.addValue(\"delete\", VKEY_DELETE);\n    kt.addValue(\"end\", VKEY_END);\n    kt.addValue(\"page_down\", VKEY_PAGEDOWN);\n    kt.addValue(\"right\", VKEY_RIGHT);\n    kt.addValue(\"left\", VKEY_LEFT);\n    kt.addValue(\"down\", VKEY_DOWN);\n    kt.addValue(\"up\", VKEY_UP);\n    kt.addValue(\"num_lock_clear\", VKEY_NUMLOCKCLEAR);\n    kt.addValue(\"kp_/\", VKEY_KP_DIVIDE);\n    kt.addValue(\"kp_*\", VKEY_KP_MULTIPLY);\n    kt.addValue(\"kp_-\", VKEY_KP_MINUS);\n    kt.addValue(\"kp_+\", VKEY_KP_PLUS);\n    kt.addValue(\"kp_enter\", VKEY_KP_ENTER);\n    kt.addValue(\"kp_1\", VKEY_KP_1);\n    kt.addValue(\"kp_2\", VKEY_KP_2);\n    kt.addValue(\"kp_3\", VKEY_KP_3);\n    kt.addValue(\"kp_4\", VKEY_KP_4);\n    kt.addValue(\"kp_5\", VKEY_KP_5);\n    kt.addValue(\"kp_6\", VKEY_KP_6);\n    kt.addValue(\"kp_7\", VKEY_KP_7);\n    kt.addValue(\"kp_8\", VKEY_KP_8);\n    kt.addValue(\"kp_9\", VKEY_KP_9);\n    kt.addValue(\"kp_0\", VKEY_KP_0);\n    kt.addValue(\"kp_.\", VKEY_KP_PERIOD);\n    kt.addValue(\"nonushbackslash\", VKEY_NONUSBACKSLASH);\n    kt.addValue(\"application\", VKEY_APPLICATION);\n    kt.addValue(\"^\", VKEY_POWER);\n    kt.addValue(\"=\", VKEY_KP_EQUALS);\n    kt.addValue(\"f13\", VKEY_F13);\n    kt.addValue(\"f14\", VKEY_F14);\n    kt.addValue(\"f15\", VKEY_F15);\n    kt.addValue(\"f16\", VKEY_F16);\n    kt.addValue(\"f17\", VKEY_F17);\n    kt.addValue(\"f18\", VKEY_F18);\n    kt.addValue(\"f19\", VKEY_F19);\n    kt.addValue(\"f20\", VKEY_F20);\n    kt.addValue(\"f21\", VKEY_F21);\n    kt.addValue(\"f22\", VKEY_F22);\n    kt.addValue(\"f23\", VKEY_F23);\n    kt.addValue(\"f24\", VKEY_F24);\n    kt.addValue(\"execute\", VKEY_EXECUTE);\n    kt.addValue(\"help\", VKEY_HELP);\n    kt.addValue(\"menu\", VKEY_MENU);\n    kt.addValue(\"select\", VKEY_SELECT);\n    kt.addValue(\"stop\", VKEY_STOP);\n    kt.addValue(\"again\", VKEY_AGAIN);\n    kt.addValue(\"undo\", VKEY_UNDO);\n    kt.addValue(\"cut\", VKEY_CUT);\n    kt.addValue(\"copy\", VKEY_COPY);\n    kt.addValue(\"paste\", VKEY_PASTE);\n    kt.addValue(\"find\", VKEY_FIND);\n    kt.addValue(\"mute\", VKEY_MUTE);\n    kt.addValue(\"volume_up\", VKEY_VOLUMEUP);\n    kt.addValue(\"volume_down\", VKEY_VOLUMEDOWN);\n    kt.addValue(\",\", VKEY_KP_COMMA);\n    kt.addValue(\"equals_as_400\", VKEY_KP_EQUALSAS400);\n    kt.addValue(\"international_1\", VKEY_INTERNATIONAL1);\n    kt.addValue(\"international_2\", VKEY_INTERNATIONAL2);\n    kt.addValue(\"international_3\", VKEY_INTERNATIONAL3);\n    kt.addValue(\"international_4\", VKEY_INTERNATIONAL4);\n    kt.addValue(\"international_5\", VKEY_INTERNATIONAL5);\n    kt.addValue(\"international_6\", VKEY_INTERNATIONAL6);\n    kt.addValue(\"international_7\", VKEY_INTERNATIONAL7);\n    kt.addValue(\"international_8\", VKEY_INTERNATIONAL8);\n    kt.addValue(\"international_9\", VKEY_INTERNATIONAL9);\n    kt.addValue(\"lang1\", VKEY_LANG1);\n    kt.addValue(\"lang2\", VKEY_LANG2);\n    kt.addValue(\"lang3\", VKEY_LANG3);\n    kt.addValue(\"lang4\", VKEY_LANG4);\n    kt.addValue(\"lang5\", VKEY_LANG5);\n    kt.addValue(\"lang6\", VKEY_LANG6);\n    kt.addValue(\"lang7\", VKEY_LANG7);\n    kt.addValue(\"lang8\", VKEY_LANG8);\n    kt.addValue(\"lang9\", VKEY_LANG9);\n    kt.addValue(\"alterase\", VKEY_ALTERASE);\n    kt.addValue(\"sysreq\", VKEY_SYSREQ);\n    kt.addValue(\"cancel\", VKEY_CANCEL);\n    kt.addValue(\"clear\", VKEY_CLEAR);\n    kt.addValue(\"prior\", VKEY_PRIOR);\n    kt.addValue(\"return2\", VKEY_RETURN2);\n    kt.addValue(\"separator\", VKEY_SEPARATOR);\n    kt.addValue(\"out\", VKEY_OUT);\n    kt.addValue(\"oper\", VKEY_OPER);\n    kt.addValue(\"clearagain\", VKEY_CLEARAGAIN);\n    kt.addValue(\"crsel\", VKEY_CRSEL);\n    kt.addValue(\"exsel\", VKEY_EXSEL);\n    kt.addValue(\"kp_00\", VKEY_KP_00);\n    kt.addValue(\"kp_000\", VKEY_KP_000);\n    kt.addValue(\"thousand_separator\", VKEY_THOUSANDSSEPARATOR);\n    kt.addValue(\"decimal_separator\", VKEY_DECIMALSEPARATOR);\n    kt.addValue(\"currency_unit\", VKEY_CURRENCYUNIT);\n    kt.addValue(\"currency_subunit\", VKEY_CURRENCYSUBUNIT);\n    kt.addValue(\"kp_(\", VKEY_KP_LEFTPAREN);\n    kt.addValue(\"kp_)\", VKEY_KP_RIGHTPAREN);\n    kt.addValue(\"kp_{\", VKEY_KP_LEFTBRACE);\n    kt.addValue(\"kp_}\", VKEY_KP_RIGHTBRACE);\n    kt.addValue(\"kp_tab\", VKEY_KP_TAB);\n    kt.addValue(\"kp_backspace\", VKEY_KP_BACKSPACE);\n    kt.addValue(\"kp_A\", VKEY_KP_A);\n    kt.addValue(\"kp_B\", VKEY_KP_B);\n    kt.addValue(\"kp_C\", VKEY_KP_C);\n    kt.addValue(\"kp_D\", VKEY_KP_D);\n    kt.addValue(\"kp_E\", VKEY_KP_E);\n    kt.addValue(\"kp_F\", VKEY_KP_F);\n    kt.addValue(\"kp_xor\", VKEY_KP_XOR);\n    kt.addValue(\"^\", VKEY_KP_POWER);\n    kt.addValue(\"%\", VKEY_KP_PERCENT);\n    kt.addValue(\"<\", VKEY_KP_LESS);\n    kt.addValue(\">\", VKEY_KP_GREATER);\n    kt.addValue(\"&\", VKEY_KP_AMPERSAND);\n    kt.addValue(\"&&\", VKEY_KP_DBLAMPERSAND);\n    kt.addValue(\"|\", VKEY_KP_VERTICALBAR);\n    kt.addValue(\"||\", VKEY_KP_DBLVERTICALBAR);\n    kt.addValue(\":\", VKEY_KP_COLON);\n    kt.addValue(\"#\", VKEY_KP_HASH);\n    kt.addValue(\"space\", VKEY_KP_SPACE);\n    kt.addValue(\"@\", VKEY_KP_AT);\n    kt.addValue(\"!\", VKEY_KP_EXCLAM);\n    kt.addValue(\"memstore\", VKEY_KP_MEMSTORE);\n    kt.addValue(\"memrecall\", VKEY_KP_MEMRECALL);\n    kt.addValue(\"memclear\", VKEY_KP_MEMCLEAR);\n    kt.addValue(\"memadd\", VKEY_KP_MEMADD);\n    kt.addValue(\"memsubtract\", VKEY_KP_MEMSUBTRACT);\n    kt.addValue(\"memmultiply\", VKEY_KP_MEMMULTIPLY);\n    kt.addValue(\"memdivide\", VKEY_KP_MEMDIVIDE);\n    kt.addValue(\"kp_+-\", VKEY_KP_PLUSMINUS);\n    kt.addValue(\"kp_clear\", VKEY_KP_CLEAR);\n    kt.addValue(\"clear_entry\", VKEY_KP_CLEARENTRY);\n    kt.addValue(\"binary\", VKEY_KP_BINARY);\n    kt.addValue(\"octal\", VKEY_KP_OCTAL);\n    kt.addValue(\"decimal\", VKEY_KP_DECIMAL);\n    kt.addValue(\"hexadecimal\", VKEY_KP_HEXADECIMAL);\n    kt.addValue(\"lctrl\", VKEY_LCTRL);\n    kt.addValue(\"lshift\", VKEY_LSHIFT);\n    kt.addValue(\"lalt\", VKEY_LALT);\n    kt.addValue(\"lgui\", VKEY_LGUI);\n    kt.addValue(\"rctrl\", VKEY_RCTRL);\n    kt.addValue(\"rshift\", VKEY_RSHIFT);\n    kt.addValue(\"ralt\", VKEY_RALT);\n    kt.addValue(\"rgui\", VKEY_RGUI);\n    kt.addValue(\"mode\", VKEY_MODE);\n    kt.addValue(\"audionext\", VKEY_AUDIONEXT);\n    kt.addValue(\"audioprev\", VKEY_AUDIOPREV);\n    kt.addValue(\"audiostop\", VKEY_AUDIOSTOP);\n    kt.addValue(\"audioplay\", VKEY_AUDIOPLAY);\n    kt.addValue(\"audiomute\", VKEY_AUDIOMUTE);\n    kt.addValue(\"mediaselect\", VKEY_MEDIASELECT);\n    kt.addValue(\"www\", VKEY_WWW);\n    kt.addValue(\"mail\", VKEY_MAIL);\n    kt.addValue(\"calculator\", VKEY_CALCULATOR);\n    kt.addValue(\"computer\", VKEY_COMPUTER);\n    kt.addValue(\"ac_search\", VKEY_AC_SEARCH);\n    kt.addValue(\"ac_home\", VKEY_AC_HOME);\n    kt.addValue(\"ac_back\", VKEY_AC_BACK);\n    kt.addValue(\"ac_forward\", VKEY_AC_FORWARD);\n    kt.addValue(\"ac_stop\", VKEY_AC_STOP);\n    kt.addValue(\"ac_refresh\", VKEY_AC_REFRESH);\n    kt.addValue(\"ac_bookmarks\", VKEY_AC_BOOKMARKS);\n    kt.addValue(\"ac_brightness_down\", VKEY_BRIGHTNESSDOWN);\n    kt.addValue(\"ac_brightness_up\", VKEY_BRIGHTNESSUP);\n    kt.addValue(\"ac_display_switch\", VKEY_DISPLAYSWITCH);\n    kt.addValue(\"kb_dillum_toggle\", VKEY_KBDILLUMTOGGLE);\n    kt.addValue(\"kb_dillum_down\", VKEY_KBDILLUMDOWN);\n    kt.addValue(\"kb_dillum_up\", VKEY_KBDILLUMUP);\n    kt.addValue(\"eject\", VKEY_EJECT);\n    kt.addValue(\"sleep\", VKEY_SLEEP);\n    kt.addValue(\"value\", VKEY_HIGHEST_VALUE);\n}"
  },
  {
    "path": "SoA/VoxPool.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxPool.h\"\n\n#include \"CAEngine.h\"\n#include \"ChunkMesher.h\"\n#include \"VoxelLightEngine.h\"\n\nWorkerData::~WorkerData() {\n    delete chunkMesher;\n    delete voxelLightEngine;\n}\n"
  },
  {
    "path": "SoA/VoxPool.h",
    "content": "///\n/// VoxPool.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 7 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// \n///\n\n#pragma once\n\n#ifndef VoxPool_h__\n#define VoxPool_h__\n\n#include <Vorb/ThreadPool.h>\n\n// Worker data for a threadPool\nclass WorkerData {\npublic:\n    ~WorkerData();\n    volatile bool waiting;\n    volatile bool stop;\n\n    // Each thread gets its own generators\n    class ChunkMesher* chunkMesher = nullptr;\n    class TerrainPatchMesher* terrainMesher = nullptr;\n    class FloraGenerator* floraGenerator = nullptr;\n    class VoxelLightEngine* voxelLightEngine = nullptr;\n};\n\ntypedef vcore::ThreadPool<WorkerData> VoxPool;\n\n#endif // VoxPool_h__\n\n\n\n"
  },
  {
    "path": "SoA/VoxelBits.h",
    "content": "///\n/// VoxelBits.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 6 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Contains utils for accessing voxel bits\n/// TODO: Use C++ bit accessors\n///\n\n#pragma once\n\n#ifndef VoxelBits_h__\n#define VoxelBits_h__\n\n//For lamp colors. Used to extract color values from the 16 bit color code\n#define LAMP_RED_MASK 0x7C00\n#define LAMP_GREEN_MASK 0x3E0\n#define LAMP_BLUE_MASK 0x1f\n#define LAMP_RED_SHIFT 10\n#define LAMP_GREEN_SHIFT 5\n#define FLORA_HEIGHT_MASK 0x1f\n#define FLORA_YPOS_MASK 0x3E0\n#define FLORA_YPOS_SHIFT 5\n//no blue shift\n\nnamespace VoxelBits {\n\n    inline ui16 getFloraHeight(ui16 b) {\n        return b & FLORA_HEIGHT_MASK;\n    }\n\n    inline ui16 getFloraPosition(ui16 b) {\n        return (b & FLORA_YPOS_MASK) >> FLORA_YPOS_SHIFT;\n    }\n\n    inline ui16 getLampRed(ui16 b) {\n        return b & LAMP_RED_MASK;\n    }\n\n    inline ui16 getLampGreen(ui16 b) {\n        return b & LAMP_GREEN_MASK;\n    }\n\n    inline ui16 getLampBlue(ui16 b) {\n        return b & LAMP_BLUE_MASK;\n    }\n\n    inline void setFloraHeight(ui16& b, ui16 floraHeight) {\n        b = (b & (~FLORA_HEIGHT_MASK)) | floraHeight;\n    }\n\n    inline void setFloraPosition(ui16& b, ui16 yPos) {\n        b = (b & (~FLORA_YPOS_MASK)) | (yPos << FLORA_YPOS_SHIFT);\n    }\n\n    inline ui16 getLampRedFromHex(ui16 color) { \n        return (color & LAMP_RED_MASK) >> LAMP_RED_SHIFT; \n    }\n\n    inline ui16 getLampGreenFromHex(ui16 color) { \n        return (color & LAMP_GREEN_MASK) >> LAMP_GREEN_SHIFT;\n    }\n\n    inline ui16 getLampBlueFromHex(ui16 color) { \n        return color & LAMP_BLUE_MASK; \n    }\n\n}\n\n#endif // VoxelBits_h__"
  },
  {
    "path": "SoA/VoxelCoordinateSpaces.h",
    "content": "///\n/// VoxelCoordinateSpaces.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 27 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Contains the voxel coordinate space definitions.\n///\n\n#pragma once\n\n#ifndef VoxelCoordinateSpaces_h__\n#define VoxelCoordinateSpaces_h__\n\n#include \"Vorb/types.h\"\n\nenum WorldCubeFace {\n    FACE_TOP = 0, FACE_LEFT, FACE_RIGHT,\n    FACE_FRONT, FACE_BACK, FACE_BOTTOM,\n    FACE_NONE\n};\n\nstruct ChunkPosition2D {\n    ChunkPosition2D():face(FACE_TOP) {}\n    operator i32v2&() { return pos; }\n    operator const i32v2&() const { return pos; }\n    union {\n        i32v2 pos;\n        UNIONIZE(i32 x;\n                 i32 z);\n    };\n    WorldCubeFace face;\n};\n\nstruct ChunkPosition3D {\n    ChunkPosition3D():face(FACE_TOP) {}\n    operator i32v2() const { return i32v2(pos.x, pos.z); }\n    operator i32v3&() { return pos; }\n    operator const i32v3&() const { return pos; }\n    union {\n        i32v3 pos;\n        UNIONIZE(i32 x;\n                 i32 y;\n                 i32 z);\n    };\n    WorldCubeFace face;\n};\n\nstruct VoxelPosition2D {\n    VoxelPosition2D():face(FACE_TOP) {}\n    operator f64v2&() { return pos; }\n    operator const f64v2&() const { return pos; }\n    union {\n        f64v2 pos;\n        UNIONIZE(f64 x;\n                 f64 z);\n    };\n    WorldCubeFace face;\n};\n\nstruct VoxelPosition3D {\n    VoxelPosition3D():face(FACE_TOP) {}\n    operator f64v2() const { return f64v2(pos.x, pos.z); }\n    operator f64v3&() { return pos; }\n    operator const f64v3&() const { return pos; }\n    union {\n        f64v3 pos;\n        UNIONIZE(f64 x;\n                 f64 y;\n                 f64 z);\n    };\n    WorldCubeFace face;\n};\n\n#endif // VoxelCoordinateSpaces_h__\n"
  },
  {
    "path": "SoA/VoxelEditor.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelEditor.h\"\n\n#include \"BlockData.h\"\n#include \"Chunk.h\"\n#include \"ChunkGrid.h\"\n#include \"ChunkUpdater.h\"\n#include \"Item.h\"\n#include \"VoxelNavigation.inl\"\n#include \"VoxelSpaceConversions.h\"\n\n// TODO: Implement and remove VORB_UNUSED tags.\n\nvoid VoxelEditor::editVoxels(ChunkGrid& grid, ItemStack* block) {\n    if (m_startPosition.x == INT_MAX || m_endPosition.x == INT_MAX) {\n        return;\n    }\n\n    switch (m_currentTool) {\n    case EDITOR_TOOLS::AABOX:\n        placeAABox(grid, block);\n        break;\n    case EDITOR_TOOLS::LINE:\n        placeLine(grid, block);\n        break;\n    }\n}\n\nvoid VoxelEditor::placeAABox(ChunkGrid& grid, ItemStack* block) {\n    //BlockID blockID;\n    // int soundNum = 0;\n    int yStart, yEnd;\n    int zStart, zEnd;\n    int xStart, xEnd;\n\n    i32v3 start = m_startPosition;\n    i32v3 end = m_endPosition;\n\n    //Set up iteration bounds\n    if (start.y < end.y) {\n        yStart = start.y;\n        yEnd = end.y;\n    } else {\n        yEnd = start.y;\n        yStart = end.y;\n    }\n\n    if (start.z < end.z) {\n        zStart = start.z;\n        zEnd = end.z;\n    } else {\n        zEnd = start.z;\n        zStart = end.z;\n    }\n\n    if (start.x < end.x) {\n        xStart = start.x;\n        xEnd = end.x;\n    } else {\n        xEnd = start.x;\n        xStart = end.x;\n    }\n\n    // Keep track of which chunk is locked\n    Chunk* chunk = nullptr;\n    ChunkID currentID(0xffffffffffffffff);\n    bool locked = false;\n\n    std::map<ChunkID, ChunkHandle> modifiedChunks;\n\n    for (int y = yStart; y <= yEnd; y++) {\n        for (int z = zStart; z <= zEnd; z++) {\n            for (int x = xStart; x <= xEnd; x++) {\n                i32v3 chunkPos = VoxelSpaceConversions::voxelToChunk(i32v3(x, y, z));\n                ChunkID id(chunkPos);\n                if (id != currentID) {\n                    currentID = id;\n                    if (chunk) {\n                        if (locked) {\n                            chunk->dataMutex.unlock();\n                            locked = false;\n                        }\n                    }\n                    // Only need to aquire once\n                    auto it = modifiedChunks.find(currentID);\n                    if (it == modifiedChunks.end()) {\n                        chunk = modifiedChunks.insert(std::make_pair(currentID, grid.accessor.acquire(id))).first->second;\n                    } else {\n                        chunk = it->second;\n                    }\n                    if (chunk->isAccessible) {\n                        chunk->dataMutex.lock();\n                        locked = true;\n                    }\n                }\n                if (locked) {\n                    i32v3 pos = i32v3(x, y, z) - chunkPos * CHUNK_WIDTH;\n                    int voxelIndex = pos.x + pos.y * CHUNK_LAYER + pos.z * CHUNK_WIDTH;\n                    // TODO: This needs implementing.\n                    //blockID = chunk->blocks.get(voxelIndex);\n\n                    if (!block) {\n                        // Breaking blocks\n                    } else {\n                        // Placing blocks\n                        block->count--;\n\n                        // ChunkUpdater::placeBlock(chunk, )\n                        ChunkUpdater::placeBlockNoUpdate(chunk, voxelIndex, block->pack->operator[](block->id).blockID);\n                        if (block->count == 0) {\n                            if (locked) chunk->dataMutex.unlock();\n                            for (auto& it : modifiedChunks) {\n                                if (it.second->isAccessible) {\n                                    it.second->DataChange(it.second);\n                                }\n                                it.second.release();\n                            }\n                            stopDragging();\n                            return;\n                        }\n                        \n                    }\n                }\n            }\n        }\n    }\n    if (locked) chunk->dataMutex.unlock();\n    for (auto& it : modifiedChunks) {\n        if (it.second->isAccessible) {\n            it.second->DataChange(it.second);\n        }\n        it.second.release();\n    }\n    stopDragging();\n}\n\nvoid VoxelEditor::stopDragging() {\n    //This means we no longer have a selection box\n    m_startPosition = i32v3(INT_MAX);\n    m_endPosition = i32v3(INT_MAX);\n}\n\nvoid VoxelEditor::placeLine(ChunkGrid& grid VORB_UNUSED, ItemStack* block VORB_UNUSED) {\n\n}\n\nbool VoxelEditor::isEditing() {\n    return (m_startPosition.x != INT_MAX && m_endPosition.x != INT_MAX);\n}\n\nvoid VoxelEditor::drawGuides(vg::GLProgram* program VORB_UNUSED, const f64v3& cameraPos VORB_UNUSED, const f32m4 &VP VORB_UNUSED, int blockID VORB_UNUSED)\n{\n    switch (m_currentTool) {\n        case EDITOR_TOOLS::AABOX:{\n                // const float BOX_PAD = 0.001f;\n\n                i32v3 startPosition;\n                startPosition.x = glm::min(m_startPosition.x, m_endPosition.x);\n                startPosition.y = glm::min(m_startPosition.y, m_endPosition.y);\n                startPosition.z = glm::min(m_startPosition.z, m_endPosition.z);\n\n                //const i32v3 size = glm::abs(m_endPosition - m_startPosition) + i32v3(1);\n\n                if (blockID != 0){\n            //      DrawWireBox(program, startPosition.x - BOX_PAD, startPosition.y - BOX_PAD, startPosition.z - BOX_PAD, size.x + BOX_PAD * 2, size.y + BOX_PAD * 2, size.z + BOX_PAD * 2, 2, cameraPos, VP, f32v4(0.0, 0.0, 1.0, 1.0));\n            //      DrawWireBox(program, startPosition.x + BOX_PAD, startPosition.y + BOX_PAD, startPosition.z + BOX_PAD, size.x - BOX_PAD * 2, size.y - BOX_PAD * 2, size.z - BOX_PAD * 2, 2, cameraPos, VP, f32v4(0.0, 0.0, 1.0, 1.0));\n                } else{\n            //      DrawWireBox(program, startPosition.x - BOX_PAD, startPosition.y - BOX_PAD, startPosition.z - BOX_PAD, size.x + BOX_PAD * 2, size.y + BOX_PAD * 2, size.z + BOX_PAD * 2, 2, cameraPos, VP, f32v4(1.0, 0.0, 0.0, 1.0));\n            //      DrawWireBox(program, startPosition.x + BOX_PAD, startPosition.y + BOX_PAD, startPosition.z + BOX_PAD, size.x - BOX_PAD * 2, size.y - BOX_PAD * 2, size.z - BOX_PAD * 2, 2, cameraPos, VP, f32v4(1.0, 0.0, 0.0, 1.0));\n                }\n            }\n            break;\n        default:\n            break;\n    }\n}"
  },
  {
    "path": "SoA/VoxelEditor.h",
    "content": "#pragma once\n#include <map>\n\n#include <Vorb/types.h>\n#include <Vorb/VorbPreDecl.inl>\n\nDECL_VG(class GLProgram);\n\nclass ChunkGrid;\nclass PhysicsEngine;\nstruct ItemStack;\n\nclass EditorNode {\n//    i32v3 position;\n};\n\nenum class EDITOR_TOOLS { AABOX, LINE };\n\nclass VoxelEditor {\npublic:    \n    void editVoxels(ChunkGrid& grid, ItemStack* block);\n\n    void stopDragging();\n\n    void setStartPosition(const i32v3& position) { m_startPosition = position; }\n    void setEndPosition(const i32v3& position) { m_endPosition = position; }   \n    void setEditorTool(EDITOR_TOOLS editorTool) { m_currentTool = editorTool; }\n\n    bool isEditing();\n\n    const i32v3& getStartPosition() const { return m_startPosition; }\n    const i32v3& getEndPosition() const { return m_endPosition; }\n\n    //Draws the guide lines\n    void drawGuides(vg::GLProgram* program, const f64v3& cameraPos, const f32m4 &VP, int blockID);\n\nprivate:\n    \n    void placeAABox(ChunkGrid& grid, ItemStack* block);\n    void placeLine(ChunkGrid& grid, ItemStack* block);\n\n    // v v v Just some ideas v v v\n    // void placeBox();\n    // void placeWireBox();\n    // void placeSlab();\n    // void placeWireSlab();\n    \n    i32v3 m_startPosition = i32v3(INT_MAX);\n    i32v3 m_endPosition = i32v3(INT_MAX);\n\n    std::vector<EditorNode> m_currentShape;\n//    bool m_isAxisAligned;\n    EDITOR_TOOLS m_currentTool = EDITOR_TOOLS::AABOX;\n};"
  },
  {
    "path": "SoA/VoxelLightEngine.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelLightEngine.h\"\n\n#include \"Errors.h\"\n#include \"VoxelNavigation.inl\"\n\n// TODO: Do we still want this system as is? If so reimplement and remove VORB_UNUSED tags.\n\nvoid VoxelLightEngine::calculateLight(Chunk* chunk VORB_UNUSED)\n{\n    ////Flush all edge queues\n    //_lockedChunk = nullptr;\n\n    ////Sunlight Calculation\n    //if (chunk->sunlightRemovalQueue.size()) {\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //    //Removal\n    //    while (chunk->sunlightRemovalQueue.size()){\n    //        auto& node = chunk->sunlightRemovalQueue.front();\n    //        removeSunlightBFS(chunk, (int)node.blockIndex, node.oldLightVal);\n    //        chunk->sunlightRemovalQueue.pop();\n    //    }\n    //    std::queue<SunlightRemovalNode>().swap(chunk->sunlightRemovalQueue); //forces memory to be freed\n    //}\n\n    //if (chunk->sunlightUpdateQueue.size()) {\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //    //Addition\n    //    while (chunk->sunlightUpdateQueue.size()){\n    //        auto& node = chunk->sunlightUpdateQueue.front();\n    //        placeSunlightBFS(chunk, (int)node.blockIndex, (int)node.lightVal);\n    //        chunk->sunlightUpdateQueue.pop();\n    //    }\n    //    std::queue<SunlightUpdateNode>().swap(chunk->sunlightUpdateQueue); //forces memory to be freed\n    //}\n\n    ////Voxel Light Calculation\n    //if (chunk->lampLightRemovalQueue.size()) {\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //    //Removal\n    //    while (chunk->lampLightRemovalQueue.size()){\n    //        auto& node = chunk->lampLightRemovalQueue.front();\n    //        removeLampLightBFS(chunk, (int)node.blockIndex, node.oldLightColor);\n    //        chunk->lampLightRemovalQueue.pop();\n    //    }\n    //    std::queue<LampLightRemovalNode>().swap(chunk->lampLightRemovalQueue); //forces memory to be freed\n    //}\n\n    //if (chunk->lampLightUpdateQueue.size()) {\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //    //Addition\n    //    while (chunk->lampLightUpdateQueue.size()) {\n    //        auto& node = chunk->lampLightUpdateQueue.front();\n    //        placeLampLightBFS(chunk, (int)node.blockIndex, node.lightColor);\n    //        chunk->lampLightUpdateQueue.pop();\n    //    }\n    //    std::queue<LampLightUpdateNode>().swap(chunk->lampLightUpdateQueue); //forces memory to be freed\n    //}\n    //if (_lockedChunk) {\n    //    _lockedChunk->unlock();\n    //    _lockedChunk = nullptr;\n    //}\n}\n\nvoid VoxelLightEngine::calculateSunlightExtend(Chunk* chunk VORB_UNUSED)\n{\n    //int blockIndex;\n    //int y;\n\n    //_lockedChunk = nullptr;\n    //vvox::swapLockedChunk(chunk, _lockedChunk);\n\n    //for (ui32 i = 0; i < chunk->sunExtendList.size(); i++){\n    //    blockIndex = chunk->sunExtendList[i];\n    //    if (chunk->getSunlight(blockIndex) == MAXLIGHT){\n    //        y = blockIndex / CHUNK_LAYER;\n    //        extendSunRay(chunk, blockIndex - y * CHUNK_LAYER, y);\n    //    }\n    //}\n    //std::vector<GLushort>().swap(chunk->sunExtendList); //forces memory to be freed\n    //if (_lockedChunk) {\n    //    _lockedChunk->unlock();\n    //    _lockedChunk = nullptr;\n    //}\n}\n\nvoid VoxelLightEngine::calculateSunlightRemoval(Chunk* chunk VORB_UNUSED)\n{\n    //int blockIndex;\n    //int y;\n\n    //_lockedChunk = nullptr;\n    //vvox::swapLockedChunk(chunk, _lockedChunk);\n\n    //for (ui32 i = 0; i < chunk->sunRemovalList.size(); i++){\n    //    blockIndex = chunk->sunRemovalList[i];\n    //    if (chunk->getSunlight(blockIndex) == 0){\n    //        y = blockIndex / CHUNK_LAYER;\n    //        blockSunRay(chunk, blockIndex - y * CHUNK_LAYER, y - 1);\n    //    }\n    //}\n    //std::vector<GLushort>().swap(chunk->sunRemovalList); //forces memory to be freed\n    //if (_lockedChunk) {\n    //    _lockedChunk->unlock();\n    //    _lockedChunk = nullptr;\n    //}\n}\n\n//Check for sun rays from the top chunk\nvoid VoxelLightEngine::checkTopForSunlight(Chunk* chunk VORB_UNUSED)\n{\n    //int blockIndex;\n    //ui16 topLight;\n\n    //static ui16 topSunlight[CHUNK_LAYER];\n\n    //if (chunk->top && chunk->top->isAccessible) {\n    //    // First grab the sunlight from the top\n    //    chunk->top->lock();\n    //    for (int i = 0; i < CHUNK_LAYER; i++) {\n    //        topSunlight[i] = chunk->top->getSunlight(i);\n    //    }\n    //    chunk->top->unlock();\n    //    // Now check for sun extend\n    //    chunk->lock();\n    //    for (int i = 0; i < CHUNK_LAYER; i++) {\n    //        blockIndex = i + 31 * CHUNK_LAYER;\n    //        topLight = topSunlight[i];\n\n    //        if ((chunk->getBlock(blockIndex).blockLight == 0) && topLight == MAXLIGHT) {\n    //            chunk->setSunlight(blockIndex, MAXLIGHT);\n    //            chunk->sunExtendList.push_back(blockIndex);\n    //        } else if (topLight == 0) { //if the top is blocking sunlight\n    //            if (chunk->getSunlight(blockIndex) == MAXLIGHT) {\n    //                chunk->setSunlight(blockIndex, 0);\n    //                chunk->sunRemovalList.push_back(blockIndex);\n    //            }\n    //        }\n    //    }\n    //    chunk->unlock();\n    //}\n}\n\nvoid VoxelLightEngine::blockSunRay(Chunk* chunk VORB_UNUSED, int xz VORB_UNUSED, int y VORB_UNUSED)\n{\n    //int i = y; //start at the current block\n    //chunk->changeState(ChunkStates::MESH);\n   \n    //while (true){ //do the light removal iteration\n    //    if (i == -1){ //bottom chunk\n    //        if (chunk->bottom && chunk->bottom->isAccessible){\n    //            vvox::swapLockedChunk(chunk->bottom, _lockedChunk);\n    //            VoxelLightEngine::blockSunRay(chunk->bottom, xz, 31); //continue the algorithm\n    //            vvox::swapLockedChunk(chunk, _lockedChunk);\n    //        }\n    //        return;\n    //    } else{\n    //        if (chunk->getSunlight(xz + i*CHUNK_LAYER) == MAXLIGHT){\n    //            chunk->setSunlight(xz + i*CHUNK_LAYER, 0);\n    //            VoxelLightEngine::removeSunlightBFS(chunk, xz + i*CHUNK_LAYER, MAXLIGHT);\n    //        } else{\n    //            return;\n    //        }\n    //        i--;\n    //    }\n    //}\n\n}\n\nvoid VoxelLightEngine::extendSunRay(Chunk* chunk VORB_UNUSED, int xz VORB_UNUSED, int y VORB_UNUSED)\n{\n    //int i = y; //start at the current block, for extension to other chunks\n    //int blockIndex;\n    //chunk->changeState(ChunkStates::MESH);\n    //while (true){\n    //    if (i == -1){\n    //        if (chunk->bottom && chunk->bottom->isAccessible){\n    //            vvox::swapLockedChunk(chunk->bottom, _lockedChunk);\n    //            extendSunRay(chunk->bottom, xz, 31); //continue the algorithm\n    //            vvox::swapLockedChunk(chunk, _lockedChunk);\n    //        }\n    //        return;\n    //    } else{\n    //        blockIndex = xz + i*CHUNK_LAYER;\n    //        if (chunk->getBlock(blockIndex).blockLight == 0){\n\n    //            if (chunk->getSunlight(blockIndex) != MAXLIGHT){\n    //                chunk->sunlightUpdateQueue.emplace(blockIndex, MAXLIGHT);\n    //            }\n    //        \n    //        } else{\n    //            return;\n    //        }\n    //    }\n    //    i--;\n    //}\n}\n\ninline void removeSunlightNeighborUpdate(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ui16 light VORB_UNUSED) {\n   /* ui8 lightVal = chunk->getSunlight(blockIndex);\n    if (lightVal > 0){\n        if (lightVal <= light){\n            chunk->setSunlight(blockIndex, 0);\n            chunk->sunlightRemovalQueue.emplace(blockIndex, light);\n        } else {\n            chunk->sunlightUpdateQueue.emplace(blockIndex, 0);\n        }\n    }*/\n}\n\nvoid VoxelLightEngine::removeSunlightBFS(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ui8 oldLightVal VORB_UNUSED)\n{\n    //ui8 nextIntensity;\n    //if (oldLightVal > 0) {\n    //    nextIntensity = oldLightVal - 1;\n    //} else {\n    //    nextIntensity = 0;\n    //}\n\n    //int x = blockIndex % CHUNK_WIDTH;\n    //int y = blockIndex / CHUNK_LAYER;\n    //int z = (blockIndex % CHUNK_LAYER) / CHUNK_WIDTH;\n\n    //Chunk*& left = chunk->left;\n    //Chunk*& right = chunk->right;\n    //Chunk*& back = chunk->back;\n    //Chunk*& front = chunk->front;\n    //Chunk*& top = chunk->top;\n    //Chunk*& bottom = chunk->bottom;\n\n    //if (x > 0){ //left\n    //    removeSunlightNeighborUpdate(chunk, blockIndex - 1, nextIntensity);\n    //} else if (left && left->isAccessible){\n    //    vvox::swapLockedChunk(left, _lockedChunk);\n    //    removeSunlightNeighborUpdate(left, blockIndex + CHUNK_WIDTH - 1, nextIntensity);\n    //    left->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (x < CHUNK_WIDTH - 1){ //right\n    //    removeSunlightNeighborUpdate(chunk, blockIndex + 1, nextIntensity);\n    //} else if (right && right->isAccessible){\n    //    vvox::swapLockedChunk(right, _lockedChunk);\n    //    removeSunlightNeighborUpdate(right, blockIndex - CHUNK_WIDTH + 1, nextIntensity);\n    //    right->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (z > 0){ //back\n    //    removeSunlightNeighborUpdate(chunk, blockIndex - CHUNK_WIDTH, nextIntensity);\n    //} else if (back && back->isAccessible){\n    //    vvox::swapLockedChunk(back, _lockedChunk);\n    //    removeSunlightNeighborUpdate(back, blockIndex + CHUNK_LAYER - CHUNK_WIDTH, nextIntensity);\n    //    back->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (z < CHUNK_WIDTH - 1){ //front\n    //    removeSunlightNeighborUpdate(chunk, blockIndex + CHUNK_WIDTH, nextIntensity);\n    //} else if (front && front->isAccessible){\n    //    vvox::swapLockedChunk(front, _lockedChunk);\n    //    removeSunlightNeighborUpdate(front, blockIndex - CHUNK_LAYER + CHUNK_WIDTH, nextIntensity);\n    //    front->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (y > 0){ //bottom\n    //    removeSunlightNeighborUpdate(chunk, blockIndex - CHUNK_LAYER, nextIntensity);\n    //} else if (bottom && bottom->isAccessible){\n    //    vvox::swapLockedChunk(bottom, _lockedChunk);\n    //    removeSunlightNeighborUpdate(bottom, CHUNK_SIZE - CHUNK_LAYER + blockIndex, nextIntensity);\n    //    bottom->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (y < CHUNK_WIDTH - 1){ //top\n    //    removeSunlightNeighborUpdate(chunk, blockIndex + CHUNK_LAYER, nextIntensity);\n    //} else if (top && top->isAccessible){\n    //    vvox::swapLockedChunk(top, _lockedChunk);\n    //    removeSunlightNeighborUpdate(top, blockIndex - CHUNK_SIZE + CHUNK_LAYER, nextIntensity);\n    //    top->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n    //chunk->changeState(ChunkStates::MESH);\n\n}\n\ninline void placeSunlightNeighborUpdate(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ui16 light VORB_UNUSED) {\n    //if (chunk->getSunlight(blockIndex) < light){\n    //    if (chunk->getBlock(blockIndex).allowLight){\n    //        chunk->setSunlight(blockIndex, (ui8)light); // TODO(Ben) Wrong type?\n    //        chunk->sunlightUpdateQueue.emplace(blockIndex, light);\n    //    }\n    //}\n}\n\nvoid VoxelLightEngine::placeSunlightBFS(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ui8 intensity VORB_UNUSED)\n{\n    //if (intensity > chunk->getSunlight(blockIndex)) {\n    //    //Set the light value\n    //    chunk->setSunlight(blockIndex, intensity);\n    //} else {\n    //    //If intensity is less that the actual light value, use the actual\n    //    intensity = chunk->getSunlight(blockIndex);\n    //}\n\n    //if (intensity <= 1) return;\n    ////Reduce by 1 to prevent a bunch of -1\n    //ui8 newIntensity = (intensity - 1);\n\n    //chunk->dirty = 1;\n\n    //int x = blockIndex % CHUNK_WIDTH;\n    //int y = blockIndex / CHUNK_LAYER;\n    //int z = (blockIndex % CHUNK_LAYER) / CHUNK_WIDTH;\n\n    //Chunk*& left = chunk->left;\n    //Chunk*& right = chunk->right;\n    //Chunk*& back = chunk->back;\n    //Chunk*& front = chunk->front;\n    //Chunk*& top = chunk->top;\n    //Chunk*& bottom = chunk->bottom;\n\n    //if (x > 0){ //left\n    //    placeSunlightNeighborUpdate(chunk, blockIndex - 1, newIntensity);\n    //} else if (left && left->isAccessible){\n    //    vvox::swapLockedChunk(left, _lockedChunk);\n    //    placeSunlightNeighborUpdate(left, blockIndex + CHUNK_WIDTH - 1, newIntensity);\n    //    left->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (x < CHUNK_WIDTH - 1){ //right\n    //    placeSunlightNeighborUpdate(chunk, blockIndex + 1, newIntensity);\n    //} else if (right && right->isAccessible){\n    //    vvox::swapLockedChunk(right, _lockedChunk);\n    //    placeSunlightNeighborUpdate(right, blockIndex - CHUNK_WIDTH + 1, newIntensity);\n    //    right->changeState(ChunkStates::MESH); \n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (z > 0){ //back\n    //    placeSunlightNeighborUpdate(chunk, blockIndex - CHUNK_WIDTH, newIntensity);\n    //} else if (back && back->isAccessible){\n    //    vvox::swapLockedChunk(back, _lockedChunk);\n    //    placeSunlightNeighborUpdate(back, blockIndex + CHUNK_LAYER - CHUNK_WIDTH, newIntensity);\n    //    back->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (z < CHUNK_WIDTH - 1){ //front\n    //    placeSunlightNeighborUpdate(chunk, blockIndex + CHUNK_WIDTH, newIntensity);\n    //} else if (front && front->isAccessible){\n    //    vvox::swapLockedChunk(front, _lockedChunk);\n    //    placeSunlightNeighborUpdate(front, blockIndex - CHUNK_LAYER + CHUNK_WIDTH, newIntensity);\n    //    front->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (y > 0){ //bottom\n    //    placeSunlightNeighborUpdate(chunk, blockIndex - CHUNK_LAYER, newIntensity);\n    //} else if (bottom && bottom->isAccessible){\n    //    vvox::swapLockedChunk(bottom, _lockedChunk);\n    //    placeSunlightNeighborUpdate(bottom, CHUNK_SIZE - CHUNK_LAYER + blockIndex, newIntensity);\n    //    bottom->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //if (y < CHUNK_WIDTH - 1){ //top\n    //    placeSunlightNeighborUpdate(chunk, blockIndex + CHUNK_LAYER, newIntensity);\n    //} else if (top && top->isAccessible){\n    //    vvox::swapLockedChunk(top, _lockedChunk);\n    //    placeSunlightNeighborUpdate(top, blockIndex - CHUNK_SIZE + CHUNK_LAYER, newIntensity);\n    //    top->changeState(ChunkStates::MESH);\n    //    vvox::swapLockedChunk(chunk, _lockedChunk);\n    //}\n\n    //chunk->changeState(ChunkStates::MESH);\n}\n\ninline ui16 getMaxLampColors(const ui16 redA VORB_UNUSED, const ui16 greenA VORB_UNUSED, const ui16 blueA VORB_UNUSED, const ui16 b VORB_UNUSED) {\n    /*   ui16 redB = b & LAMP_RED_MASK;\n       ui16 greenB = b & LAMP_GREEN_MASK;\n       ui16 blueB = b & LAMP_BLUE_MASK;\n       return MAX(redA, redB) | MAX(greenA, greenB) | MAX(blueA, blueB);*/\n       return 0;\n}\n\ninline void getLampColors(const ui16 l VORB_UNUSED, ui16 &r VORB_UNUSED, ui16 &g VORB_UNUSED, ui16 &b VORB_UNUSED) {\n    /*  r = l & LAMP_RED_MASK;\n      g = l & LAMP_GREEN_MASK;\n      b = l & LAMP_BLUE_MASK;*/\n}\n\ninline void removeLampNeighborUpdate(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ui16 intensityRed VORB_UNUSED, ui16 intensityGreen VORB_UNUSED, ui16 intensityBlue VORB_UNUSED, ui16 light VORB_UNUSED) {\n   /* ui16 nextRed, nextGreen, nextBlue;\n    ui16 nextLight = chunk->getLampLight(blockIndex);\n    getLampColors(nextLight, nextRed, nextGreen, nextBlue);\n\n    if ((nextRed && nextRed <= intensityRed) || (nextGreen && nextGreen <= intensityGreen) || (nextBlue && nextBlue <= intensityBlue)){\n        chunk->setLampLight(blockIndex, 0);\n        chunk->lampLightRemovalQueue.emplace(blockIndex, light);\n\n        if (nextRed > intensityRed || nextGreen > intensityGreen || nextBlue > intensityBlue){\n            chunk->lampLightUpdateQueue.emplace(blockIndex, 0);\n        }\n    } else if (nextLight > 0) {\n        chunk->lampLightUpdateQueue.emplace(blockIndex, 0);\n    }*/\n}\n\nvoid VoxelLightEngine::removeLampLightBFS(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ui16 light VORB_UNUSED)\n{\n//#define RED1 0x400\n//#define GREEN1 0x20\n//#define BLUE1 1\n//\n//    ui16 intensityRed = light & LAMP_RED_MASK;\n//    ui16 intensityGreen = light & LAMP_GREEN_MASK;\n//    ui16 intensityBlue = light & LAMP_BLUE_MASK;\n//\n//    //Reduce by 1\n//    if (intensityRed != 0) {\n//        intensityRed -= RED1;\n//        light -= RED1;\n//    }\n//    if (intensityGreen != 0) {\n//        intensityGreen -= GREEN1;\n//        light -= GREEN1;\n//    }\n//    if (intensityBlue != 0) {\n//        intensityBlue -= BLUE1;\n//        light -= BLUE1;\n//    }\n//\n//    int x = blockIndex % CHUNK_WIDTH;\n//    int y = blockIndex / CHUNK_LAYER;\n//    int z = (blockIndex % CHUNK_LAYER) / CHUNK_WIDTH;\n//\n//    Chunk*& left = chunk->left;\n//    Chunk*& right = chunk->right;\n//    Chunk*& back = chunk->back;\n//    Chunk*& front = chunk->front;\n//    Chunk*& top = chunk->top;\n//    Chunk*& bottom = chunk->bottom;\n//\n//    if (x > 0){ //left\n//        removeLampNeighborUpdate(chunk, blockIndex - 1, intensityRed, intensityGreen, intensityBlue, light);    \n//    } else if (left && left->isAccessible){\n//        vvox::swapLockedChunk(left, _lockedChunk);\n//        removeLampNeighborUpdate(left, blockIndex + CHUNK_WIDTH - 1, intensityRed, intensityGreen, intensityBlue, light);\n//        left->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (x < CHUNK_WIDTH - 1){ //right\n//        removeLampNeighborUpdate(chunk, blockIndex + 1, intensityRed, intensityGreen, intensityBlue, light);\n//    } else if (right && right->isAccessible){\n//        vvox::swapLockedChunk(right, _lockedChunk);\n//        removeLampNeighborUpdate(right, blockIndex - CHUNK_WIDTH + 1, intensityRed, intensityGreen, intensityBlue, light);\n//        right->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (z > 0){ //back\n//        removeLampNeighborUpdate(chunk, blockIndex - CHUNK_WIDTH, intensityRed, intensityGreen, intensityBlue, light);\n//    } else if (back && back->isAccessible){\n//        vvox::swapLockedChunk(back, _lockedChunk);\n//        removeLampNeighborUpdate(back, blockIndex + CHUNK_LAYER - CHUNK_WIDTH, intensityRed, intensityGreen, intensityBlue, light);\n//        back->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (z < CHUNK_WIDTH - 1){ //front\n//        removeLampNeighborUpdate(chunk, blockIndex + CHUNK_WIDTH, intensityRed, intensityGreen, intensityBlue, light);\n//    } else if (front && front->isAccessible){\n//        vvox::swapLockedChunk(front, _lockedChunk);\n//        removeLampNeighborUpdate(front, blockIndex - CHUNK_LAYER + CHUNK_WIDTH, intensityRed, intensityGreen, intensityBlue, light);\n//        front->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (y > 0){ //bottom\n//        removeLampNeighborUpdate(chunk, blockIndex - CHUNK_LAYER, intensityRed, intensityGreen, intensityBlue, light);\n//    } else if (bottom && bottom->isAccessible){\n//        vvox::swapLockedChunk(bottom, _lockedChunk);\n//        removeLampNeighborUpdate(bottom, CHUNK_SIZE - CHUNK_LAYER + blockIndex, intensityRed, intensityGreen, intensityBlue, light);\n//        bottom->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (y < CHUNK_WIDTH - 1){ //top\n//        removeLampNeighborUpdate(chunk, blockIndex + CHUNK_LAYER, intensityRed, intensityGreen, intensityBlue, light);\n//    } else if (top && top->isAccessible){\n//        vvox::swapLockedChunk(top, _lockedChunk);\n//        removeLampNeighborUpdate(top, blockIndex - CHUNK_SIZE + CHUNK_LAYER, intensityRed, intensityGreen, intensityBlue, light);\n//        top->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//    chunk->changeState(ChunkStates::MESH);\n\n}\n\ninline void placeLampNeighborUpdate(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ui16 intensityRed VORB_UNUSED, ui16 intensityGreen VORB_UNUSED, ui16 intensityBlue VORB_UNUSED) {\n  /*  ui16 currentLight = chunk->getLampLight(blockIndex);\n    const Block& block = chunk->getBlock(blockIndex);\n\n    intensityRed = (ui16)((intensityRed >> LAMP_RED_SHIFT) * block.colorFilter.r) << LAMP_RED_SHIFT;\n    intensityGreen = (ui16)((intensityGreen >> LAMP_GREEN_SHIFT) * block.colorFilter.g) << LAMP_GREEN_SHIFT;\n    intensityBlue = (ui16)(intensityBlue * block.colorFilter.b);\n\n    ui16 nextLight = getMaxLampColors(intensityRed, intensityGreen, intensityBlue, currentLight);\n    if (nextLight != currentLight){\n        if (chunk->getBlock(blockIndex).allowLight){\n            chunk->setLampLight(blockIndex, nextLight);\n            chunk->lampLightUpdateQueue.emplace(blockIndex, nextLight);\n        }\n    }*/\n}\n\nvoid VoxelLightEngine::placeLampLightBFS(Chunk* chunk VORB_UNUSED, int blockIndex VORB_UNUSED, ui16 intensity VORB_UNUSED)\n{\n//#define RED1 0x400\n//#define GREEN1 0x20\n//#define BLUE1 1\n//\n//    ui16 currentLight = chunk->getLampLight(blockIndex);\n//\n//    ui16 currentRed = currentLight & LAMP_RED_MASK;\n//    ui16 currentGreen = currentLight & LAMP_GREEN_MASK;\n//    ui16 currentBlue = currentLight & LAMP_BLUE_MASK;\n//\n//    ui16 intensityRed = intensity & LAMP_RED_MASK;\n//    ui16 intensityGreen = intensity & LAMP_GREEN_MASK;\n//    ui16 intensityBlue = intensity & LAMP_BLUE_MASK;\n//\n//    intensityRed = MAX(currentRed, intensityRed);\n//    intensityGreen = MAX(currentGreen, intensityGreen);\n//    intensityBlue = MAX(currentBlue, intensityBlue);\n//\n//    const Block& currentBlock = chunk->getBlock(blockIndex);\n//\n//    intensityRed = (ui16)((intensityRed >> LAMP_RED_SHIFT) * currentBlock.colorFilter.r) << LAMP_RED_SHIFT;\n//    intensityGreen = (ui16)((intensityGreen >> LAMP_GREEN_SHIFT) * currentBlock.colorFilter.g) << LAMP_GREEN_SHIFT;\n//    intensityBlue = (ui16)(intensityBlue * currentBlock.colorFilter.b);\n//    intensity = intensityRed | intensityGreen | intensityBlue;\n//\n//    if (intensity != currentLight) { \n//        //Set the light value\n//        chunk->setLampLight(blockIndex, intensity);\n//    }\n//\n//    if (intensityRed <= RED1 && intensityGreen <= GREEN1 && intensityBlue <= BLUE1) return;\n//    //Reduce by 1\n//    if (intensityRed != 0) {\n//        intensityRed -= RED1;\n//        intensity -= RED1;\n//    }\n//    if (intensityGreen != 0) {\n//        intensityGreen -= GREEN1;\n//        intensity -= GREEN1;\n//    }\n//    if (intensityBlue != 0) {\n//        intensityBlue -= BLUE1;\n//        intensity -= BLUE1;\n//    }\n//\n//    chunk->dirty = 1;\n//\n//    int x = blockIndex % CHUNK_WIDTH;\n//    int y = blockIndex / CHUNK_LAYER;\n//    int z = (blockIndex % CHUNK_LAYER) / CHUNK_WIDTH;\n//\n//    Chunk*& left = chunk->left;\n//    Chunk*& right = chunk->right;\n//    Chunk*& back = chunk->back;\n//    Chunk*& front = chunk->front;\n//    Chunk*& top = chunk->top;\n//    Chunk*& bottom = chunk->bottom;\n//\n//    if (x > 0){ //left\n//        placeLampNeighborUpdate(chunk, blockIndex - 1, intensityRed, intensityGreen, intensityBlue);\n//    } else if (left && left->isAccessible){\n//        vvox::swapLockedChunk(left, _lockedChunk);\n//        placeLampNeighborUpdate(left, blockIndex + CHUNK_WIDTH - 1, intensityRed, intensityGreen, intensityBlue);\n//        left->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (x < CHUNK_WIDTH - 1){ //right\n//        placeLampNeighborUpdate(chunk, blockIndex + 1, intensityRed, intensityGreen, intensityBlue);\n//    } else if (right && right->isAccessible){\n//        vvox::swapLockedChunk(right, _lockedChunk);\n//        placeLampNeighborUpdate(right, blockIndex - CHUNK_WIDTH + 1, intensityRed, intensityGreen, intensityBlue);\n//        right->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (z > 0){ //back\n//        placeLampNeighborUpdate(chunk, blockIndex - CHUNK_WIDTH, intensityRed, intensityGreen, intensityBlue);\n//    } else if (back && back->isAccessible){\n//        vvox::swapLockedChunk(back, _lockedChunk);\n//        placeLampNeighborUpdate(back, blockIndex + CHUNK_LAYER - CHUNK_WIDTH, intensityRed, intensityGreen, intensityBlue);\n//        back->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (z < CHUNK_WIDTH - 1){ //front\n//        placeLampNeighborUpdate(chunk, blockIndex + CHUNK_WIDTH, intensityRed, intensityGreen, intensityBlue);\n//    } else if (front && front->isAccessible){\n//        vvox::swapLockedChunk(front, _lockedChunk);\n//        placeLampNeighborUpdate(front, blockIndex - CHUNK_LAYER + CHUNK_WIDTH, intensityRed, intensityGreen, intensityBlue);\n//        front->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    if (y > 0){ //bottom\n//        placeLampNeighborUpdate(chunk, blockIndex - CHUNK_LAYER, intensityRed, intensityGreen, intensityBlue);\n//    } else if (bottom && bottom->isAccessible){\n//        vvox::swapLockedChunk(bottom, _lockedChunk);\n//        placeLampNeighborUpdate(bottom, CHUNK_SIZE - CHUNK_LAYER + blockIndex, intensityRed, intensityGreen, intensityBlue);\n//        bottom->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//    if (y < CHUNK_WIDTH - 1){ //top\n//        placeLampNeighborUpdate(chunk, blockIndex + CHUNK_LAYER, intensityRed, intensityGreen, intensityBlue);\n//    } else if (top && top->isAccessible){\n//        vvox::swapLockedChunk(top, _lockedChunk);\n//        placeLampNeighborUpdate(top, blockIndex - CHUNK_SIZE + CHUNK_LAYER, intensityRed, intensityGreen, intensityBlue);\n//        top->changeState(ChunkStates::MESH);\n//        vvox::swapLockedChunk(chunk, _lockedChunk);\n//    }\n//\n//    chunk->changeState(ChunkStates::MESH);\n}"
  },
  {
    "path": "SoA/VoxelLightEngine.h",
    "content": "#pragma once\n\n#include <Vorb/types.h>\n\n//Used to tell neighbors to update light\n//class LightMessage {\n//    LightMessage() {};\n//    LightMessage(ui16 BlockIndex, ui8 LightType, i8 LightValue) : blockIndex(BlockIndex), lightType(LightType), lightValue(LightValue) {}\n//    ui16 blockIndex;\n//    ui8 lightType;\n//    i8 lightValue;\n//};\n\nclass SunlightRemovalNode\n{\npublic:\n    SunlightRemovalNode(ui16 BlockIndex, ui8 OldLightVal) : blockIndex(BlockIndex), oldLightVal(OldLightVal){}\n    ui16 blockIndex;\n    ui8 oldLightVal;\n};\n\nclass SunlightUpdateNode\n{\npublic:\n    SunlightUpdateNode(ui16 BlockIndex, ui8 LightVal) : blockIndex(BlockIndex), lightVal(LightVal){}\n    ui16 blockIndex;\n    ui8 lightVal;\n};\n\nclass LampLightRemovalNode\n{\npublic:\n    LampLightRemovalNode(ui16 BlockIndex, ui16 OldLightColor) : blockIndex(BlockIndex), oldLightColor(OldLightColor){}\n    ui16 blockIndex;\n    ui16 oldLightColor;\n};\n\nclass LampLightUpdateNode\n{\npublic:\n    LampLightUpdateNode(ui16 BlockIndex, ui16 LightColor) : blockIndex(BlockIndex), lightColor(LightColor){}\n    ui16 blockIndex;\n    ui16 lightColor;\n};\n\nclass Chunk;\n\nclass VoxelLightEngine {\npublic:\n    void calculateLight(Chunk* chunk);\n    void calculateSunlightExtend(Chunk* chunk);\n    void calculateSunlightRemoval(Chunk* chunk);\n\n    void checkTopForSunlight(Chunk* chunk);\nprivate:\n   \n    void blockSunRay(Chunk* chunk, int xz, int y);\n    void extendSunRay(Chunk* chunk, int xz, int y);\n    void removeSunlightBFS(Chunk* chunk, int blockIndex, ui8 oldLightVal);\n    void placeSunlightBFS(Chunk* chunk, int blockIndex, ui8 intensity);\n    void removeLampLightBFS(Chunk* chunk, int blockIndex, ui16 light);\n    void placeLampLightBFS(Chunk* chunk, int blockIndex, ui16 intensity);\n\n//    Chunk* _lockedChunk = nullptr;\n};"
  },
  {
    "path": "SoA/VoxelMatrix.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelMatrix.h\"\n\n#include <Vorb/colors.h>\n\nconst ColorRGBA8& VoxelMatrix::getColor(const int index) const {\n    return data[index];\n}\n\nconst ColorRGBA8& VoxelMatrix::getColor(const i32v3& position) const {\n    return data[position.x + position.y * size.x + position.z * size.x * size.y];\n}\n\nconst ColorRGBA8& VoxelMatrix::getColor(const i32 x, const i32 y, const i32 z) const {\n    return data[x + y * size.x + z * size.x * size.y];\n}\n\nconst ColorRGBA8& VoxelMatrix::getColorAndCheckBounds(const i32v3& position) const {\n    if (position.x < 0 || position.x >= (i32)size.x) return color::Transparent;\n    if (position.y < 0 || position.y >= (i32)size.y) return color::Transparent;\n    if (position.z < 0 || position.z >= (i32)size.z) return color::Transparent;\n    return data[position.x + position.y * size.x + position.z * size.x * size.y];\n}\n\nconst ColorRGBA8& VoxelMatrix::getColorAndCheckBounds(const i32 x, const i32 y, const i32 z) const {\n    if (x < 0 || x >= (i32)size.x) return color::Transparent;\n    if (y < 0 || y >= (i32)size.y) return color::Transparent;\n    if (z < 0 || z >= (i32)size.z) return color::Transparent;\n    return data[x + y * size.x + z * size.x * size.y];\n}\n\nbool VoxelMatrix::isInterior(const i32v3& position) const {\n    if (getColorAndCheckBounds(position + i32v3(1, 0, 0)).a == 0) return false;\n    if (getColorAndCheckBounds(position + i32v3(0, 1, 0)).a == 0) return false;\n    if (getColorAndCheckBounds(position + i32v3(0, 0, 1)).a == 0) return false;\n    if (getColorAndCheckBounds(position + i32v3(-1, 0, 0)).a == 0) return false;\n    if (getColorAndCheckBounds(position + i32v3(0, -1, 0)).a == 0) return false;\n    if (getColorAndCheckBounds(position + i32v3(0, 0, -1)).a == 0) return false;\n    return true;\n}\n\nbool VoxelMatrix::isInterior(const i32 x, const i32 y, const i32 z) const {\n    return isInterior(i32v3(x, y, z));\n}"
  },
  {
    "path": "SoA/VoxelMatrix.h",
    "content": "#pragma once\n#ifndef VoxelMatrix_h__\n#define VoxelMatrix_h__\n\n#include \"Vorb/types.h\"\n\nclass VoxelMatrix {\npublic:\n    const ColorRGBA8& getColor(const int index) const;\n\n    const ColorRGBA8& getColor(const i32v3& position) const;\n    const ColorRGBA8& getColor(const i32 x, const i32 y, const i32 z) const;\n\n    const ColorRGBA8& getColorAndCheckBounds(const i32v3& position) const;\n    const ColorRGBA8& getColorAndCheckBounds(const i32 x, const i32 y, const i32 z) const;\n\n    inline ui32 getIndex(const i32v3& position) const {\n       return position.x + position.y * size.x + position.z * size.x * size.y;\n    }\n\n    inline ui32 getIndex(const i32 x, const i32 y, const i32 z) const {\n        return x + y * size.x + z * size.x * size.y;\n    }\n\n    bool isInterior(const i32v3& position) const;\n    bool isInterior(const i32 x, const i32 y, const i32 z) const;\n\n    void dispose() {\n        delete[] data;\n        data = nullptr;\n    }\n\n    nString name = \"\";\n    ui32v3 size;\n    i32v3 position;\n    ColorRGBA8* data = nullptr;\n};\n\n#endif //VoxelMatrix_h__"
  },
  {
    "path": "SoA/VoxelMesh.h",
    "content": "///\n/// VoxelMesh.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 24 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Graphics data for a voxel mesh\n///\n\n#pragma once\n\n#ifndef VoxelMesh_h__\n#define VoxelMesh_h__\n\n#include <Vorb/gtypes.h>\n\n/// Mesh data in a specific direction\nstruct VoxelFaceDirectionMesh {\npublic:\n    VGVertexBuffer verts = 0; ///< Vertex data\n    VGVertexArray vertexDeclarationSolid = 0; ///< Binding information for solid blocks\n    VGVertexArray vertexDeclarationTransparent = 0; ///< Binding information for transparent blocks\n\n    ui32 numSolid = 0; ///< Number of solid faces\n    ui32 numTransparent = 0; ///< Number of transparent faces\n};\n\n/// Mesh data for solid and transparent blocks\nstruct VoxelMesh {\npublic:\n    VoxelFaceDirectionMesh meshes[6]; ///< Voxel mesh data for all 6 faces\n    VGIndexBuffer indices = 0; ///< Reference to quad index buffer\n};\n\n#endif // VoxelMesh_h__"
  },
  {
    "path": "SoA/VoxelMesher.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelMesher.h\"\n\n// cube //\n//    v6----- v5\n//   /|      /|\n//  v1------v0|\n//  | |     | |\n//  | |v7---|-|v4\n//  |/      |/\n//  v2------v3 \n\nconst GLfloat VoxelMesher::leafVertices[72] = { -0.0f, 1.0f, 0.5f, -0.0f, -0.0f, 0.5f, 1.0f, -0.0f, 0.5f, 1.0f, 1.0f, 0.5f,  // v1-v2-v3-v0 (front) //WRONG!!!\n\n    0.5f, 1.0f, 1.0f, 0.5f, -0.0f, 1.0f, 0.5f, -0.0f, -0.0f, 0.5f, 1.0f, -0.0f,     // v0-v3-v4-v5 (right) //WRONG!!!\n\n    -0.0f, 0.5f, -0.0f, -0.0f, 0.5f, 1.0f, 1.0f, 0.5f, 1.0f, 1.0f, 0.5f, -0.0f,    // v6-v1-v0-v5 (top) //WRONG!!!\n\n    0.5f, 1.0f, -0.0f, 0.5f, -0.0f, -0.0f, 0.5f, -0.0f, 1.0f, 0.5f, 1.0f, 1.0f,   // v6-v7-v2-v1 (left) //WRONG!!!\n\n    -0.0f, 0.5f, -0.0f, 1.0f, 0.5f, -0.0f, 1.0f, 0.5f, 1.0f, -0.0f, 0.5f, 1.0f,    // v7-v4-v3-v2 (bottom) //WRONG!!!\n\n    1.0f, 1.0f, 0.5f, 1.0f, -0.0f, 0.5f, -0.0f, -0.0f, 0.5f, -0.0f, 1.0f, 0.5f };     // v5-v4-v7-v6 (back) //WRONG!!!\n\n// Cube Vertex Positional Resolution\n#define C_RES 7\n\nconst ui8v3 VoxelMesher::VOXEL_POSITIONS[NUM_FACES][4] = {\n    { ui8v3(0, C_RES, 0), ui8v3(0, 0, 0), ui8v3(0, 0, C_RES), ui8v3(0, C_RES, C_RES) }, // v6-v7-v2-v1 (left)\n    { ui8v3(C_RES, C_RES, C_RES), ui8v3(C_RES, 0, C_RES), ui8v3(C_RES, 0, 0), ui8v3(C_RES, C_RES, 0) }, // v0-v3-v4-v5 (right)\n    { ui8v3(0, 0, C_RES), ui8v3(0, 0, 0), ui8v3(C_RES, 0, 0), ui8v3(C_RES, 0, C_RES) }, // v2-v7-v4-v3 (bottom)\n    { ui8v3(C_RES, C_RES, C_RES), ui8v3(C_RES, C_RES, 0), ui8v3(0, C_RES, 0), ui8v3(0, C_RES, C_RES) }, // v0-v5-v6-v1 (top)\n    { ui8v3(C_RES, C_RES, 0), ui8v3(C_RES, 0, 0), ui8v3(0, 0, 0), ui8v3(0, C_RES, 0) }, // v5-v4-v7-v6 (back)\n    { ui8v3(0, C_RES, C_RES), ui8v3(0, 0, C_RES), ui8v3(C_RES, 0, C_RES), ui8v3(C_RES, C_RES, C_RES) } // v1-v2-v3-v0 (front)\n};\n\n//0 = x, 1 = y, 2 = z\nconst int VoxelMesher::cubeFaceAxis[6][2] = { { 0, 1 }, { 2, 1 }, { 0, 2 }, { 2, 1 }, { 0, 2 }, { 0, 1 } }; // front, right, top, left, bottom, back, for U and V respectively\n\nconst int VoxelMesher::cubeFaceAxisSign[6][2] = { { 1, 1 }, { -1, 1 }, { 1, -1 }, { 1, 1 }, { -1, -1 }, { -1, 1 } }; // front, right, top, left, bottom, back, for U and V respectively\n\nconst GLfloat VoxelMesher::liquidVertices[72] = { 0, 1.0f, 1.0f, 0, 0, 1.0f, 1.0f, 0, 1.0f, 1.0f, 1.0f, 1.0f,  // v1-v2-v3-v0 (front)\n\n    1.0f, 1.0f, 1.0f, 1.0f, 0, 1.0f, 1.0f, 0, 0, 1.0f, 1.0f, 0,     // v0-v3-v4-v5 (right)\n\n    0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0,    // v6-v1-v0-v5 (top)\n\n    0, 1.0f, 0, 0, 0, 0, 0, 0, 1.0f, 0, 1.0f, 1.0f,   // v6-v1.0f-v2-v1 (left)\n\n    1.0f, 0, 0, 1.0f, 0, 1.0f, 0, 0, 1.0f, 0, 0, 0,  // v4-v3-v2-v1.0f (bottom)\n\n    1.0f, 1.0f, 0, 1.0f, 0, 0, 0, 0, 0, 0, 1.0f, 0 };     // v5-v4-v1.0f-v6 (back)\n\n\nconst float wyOff = 0.9999f;\nconst GLfloat VoxelMesher::waterCubeVertices[72] = { 0.0f, wyOff, 1.000f, 0.0f, 0.0f, 1.000f, 1.000f, 0.0f, wyOff, 1.000f, wyOff, 1.000f,  // v1-v2-v3-v0 (front)\n\n    1.000f, wyOff, 1.000f, 1.000f, 0.0f, 1.000f, 1.000f, 0.0f, 0.0f, 1.000f, wyOff, 0.0f,     // v0-v3-v4-v5 (right)\n\n    0.0f, wyOff, 0.0f, 0.0f, wyOff, 1.000f, 1.000f, wyOff, 1.000f, 1.000f, wyOff, 0.0f,    // v6-v1-v0-v5 (top)\n\n    0.0f, wyOff, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.000f, 0.0f, wyOff, 1.000f,   // v6-v7-v2-v1 (left)\n\n    0.0f, 0.0f, 0.0f, 1.000f, 0.0f, 0.0f, 1.000f, 0.0f, 1.000f, 0.0f, 0.0f, 1.000f,    // v7-v4-v3-v2 (bottom)\n\n    1.000f, wyOff, 0.0f, 1.000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, wyOff, 0.0f };     // v5-v4-v7-v6 (back)\n\n// 1 for normalized bytes\n#define N_1 127\n\nconst GLbyte VoxelMesher::cubeNormals[72] = { 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1,  // v1-v2-v3-v0 (front)\n\n    N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0,     // v0-v3-v4-v5 (right)\n\n    0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0,    // v6-v1-v0-v5 (top)\n\n    -N_1, 0, 0, -N_1, 0, 0, -N_1, 0, 0, -N_1, 0, 0,   // v6-v7-v2-v1 (left)\n\n    0, -N_1, 0, 0, -N_1, 0, 0, -N_1, 0, 0, -N_1, 0,    // v4-v3-v2-v7  (bottom)\n\n    0, 0, -N_1, 0, 0, -N_1, 0, 0, -N_1, 0, 0, -N_1 };     // v5-v4-v7-v6 (back)\n\n//For flora, normal is strait up\nconst GLbyte VoxelMesher::floraNormals[72] = { 0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0,\n    0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0,\n    0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0,\n    0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0,\n    0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0,\n    0, N_1, 0, 0, N_1, 0, 0, N_1, 0, 0, N_1, 0 };\n\n//We use 4 meshes so that we can add variation to the flora meshes\nconst ui8v3 VoxelMesher::floraVertices[NUM_FLORA_MESHES][12] = {\n    {\n        ui8v3(0, 7, 5), ui8v3(0, 0, 5), ui8v3(7, 0, 5), ui8v3(7, 7, 5),\n        ui8v3(6, 7, 7), ui8v3(6, 0, 7), ui8v3(1, 0, 0), ui8v3(1, 7, 0),\n        ui8v3(1, 7, 7), ui8v3(1, 0, 7), ui8v3(6, 0, 0), ui8v3(6, 7, 0) },\n    {\n        ui8v3(2, 7, 0), ui8v3(2, 0, 0), ui8v3(2, 0, 7), ui8v3(2, 7, 7),\n        ui8v3(0, 7, 1), ui8v3(0, 0, 1), ui8v3(7, 0, 6), ui8v3(7, 7, 6),\n        ui8v3(0, 7, 6), ui8v3(0, 0, 6), ui8v3(7, 0, 1), ui8v3(7, 7, 1) },\n    {\n        ui8v3(0, 7, 2), ui8v3(0, 0, 2), ui8v3(7, 0, 2), ui8v3(7, 7, 2),\n        ui8v3(6, 7, 0), ui8v3(6, 0, 0), ui8v3(1, 0, 7), ui8v3(1, 7, 7),\n        ui8v3(1, 7, 0), ui8v3(1, 0, 0), ui8v3(6, 0, 7), ui8v3(6, 7, 7) },\n    {\n        ui8v3(5, 7, 0), ui8v3(5, 0, 0), ui8v3(5, 0, 7), ui8v3(5, 7, 7),\n        ui8v3(7, 7, 1), ui8v3(7, 0, 1), ui8v3(0, 0, 6), ui8v3(0, 7, 6),\n        ui8v3(7, 7, 6), ui8v3(7, 0, 6), ui8v3(0, 0, 1), ui8v3(0, 7, 1) } };\n\nconst ui8v3 VoxelMesher::crossFloraVertices[NUM_CROSSFLORA_MESHES][8] = {\n    {\n        ui8v3(0, 7, 0), ui8v3(0, 0, 0), ui8v3(7, 0, 7), ui8v3(7, 7, 7),\n        ui8v3(0, 7, 7), ui8v3(0, 0, 7), ui8v3(7, 0, 0), ui8v3(7, 7, 0) },\n    {\n        ui8v3(7, 7, 7), ui8v3(7, 0, 7), ui8v3(0, 0, 0), ui8v3(0, 7, 0),\n        ui8v3(7, 7, 0), ui8v3(7, 0, 0), ui8v3(0, 0, 7), ui8v3(0, 7, 7) } };\n\n\nvoid VoxelMesher::makeFloraFace(BlockVertex *Verts VORB_UNUSED, const ui8* positions VORB_UNUSED, const i8* normals VORB_UNUSED, int vertexOffset VORB_UNUSED, int waveEffect VORB_UNUSED, i32v3& pos VORB_UNUSED, int vertexIndex VORB_UNUSED, int textureIndex VORB_UNUSED, int overlayTextureIndex VORB_UNUSED, const ColorRGB8& color VORB_UNUSED, const ColorRGB8& overlayColor VORB_UNUSED, const ui8 sunlight VORB_UNUSED, const ColorRGB8& lampColor VORB_UNUSED, const BlockTexture* texInfo VORB_UNUSED)\n{\n// TODO: Do we still want this? If so, reimplement and remove VORB_UNUSED tags.\n//    // 7 per coord\n//    pos.x *= POSITION_RESOLUTION;\n//    pos.y *= POSITION_RESOLUTION;\n//    pos.z *= POSITION_RESOLUTION;\n//\n//    //Blend type. The 6 LSBs are used to encode alpha blending, add/subtract, and multiplication factors.\n//    //They are used in the shader to determine how to blend.\n//    ui8 blendMode = getBlendMode(texInfo->blendMode);\n//\n//    Verts[vertexIndex].blendMode = blendMode;\n//    Verts[vertexIndex + 1].blendMode = blendMode;\n//    Verts[vertexIndex + 2].blendMode = blendMode;\n//    Verts[vertexIndex + 3].blendMode = blendMode;\n//\n//    GLubyte texAtlas = (GLubyte)(textureIndex / ATLAS_SIZE);\n//    textureIndex %= ATLAS_SIZE;\n//\n//    GLubyte overlayTexAtlas = (GLubyte)(overlayTextureIndex / ATLAS_SIZE);\n//    GLubyte overlayTex = (GLubyte)(overlayTextureIndex % ATLAS_SIZE);\n//\n//    Verts[vertexIndex].textureWidth = (ubyte)texInfo->base.size.x;\n//    Verts[vertexIndex].textureHeight = (ubyte)texInfo->base.size.y;\n//    Verts[vertexIndex + 1].textureWidth = (ubyte)texInfo->base.size.x;\n//    Verts[vertexIndex + 1].textureHeight = (ubyte)texInfo->base.size.y;\n//    Verts[vertexIndex + 2].textureWidth = (ubyte)texInfo->base.size.x;\n//    Verts[vertexIndex + 2].textureHeight = (ubyte)texInfo->base.size.y;\n//    Verts[vertexIndex + 3].textureWidth = (ubyte)texInfo->base.size.x;\n//    Verts[vertexIndex + 3].textureHeight = (ubyte)texInfo->base.size.y;\n//\n//    Verts[vertexIndex].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n//    Verts[vertexIndex].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n//    Verts[vertexIndex + 1].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n//    Verts[vertexIndex + 1].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n//    Verts[vertexIndex + 2].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n//    Verts[vertexIndex + 2].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n//    Verts[vertexIndex + 3].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n//    Verts[vertexIndex + 3].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n//\n//    Verts[vertexIndex].position.x = pos.x + positions[vertexOffset];\n//    Verts[vertexIndex].position.y = pos.y + positions[vertexOffset + 1];\n//    Verts[vertexIndex].position.z = pos.z + positions[vertexOffset + 2];\n//    Verts[vertexIndex + 1].position.x = pos.x + positions[vertexOffset + 3];\n//    Verts[vertexIndex + 1].position.y = pos.y + positions[vertexOffset + 4];\n//    Verts[vertexIndex + 1].position.z = pos.z + positions[vertexOffset + 5];\n//    Verts[vertexIndex + 2].position.x = pos.x + positions[vertexOffset + 6];\n//    Verts[vertexIndex + 2].position.y = pos.y + positions[vertexOffset + 7];\n//    Verts[vertexIndex + 2].position.z = pos.z + positions[vertexOffset + 8];\n//    Verts[vertexIndex + 3].position.x = pos.x + positions[vertexOffset + 9];\n//    Verts[vertexIndex + 3].position.y = pos.y + positions[vertexOffset + 10];\n//    Verts[vertexIndex + 3].position.z = pos.z + positions[vertexOffset + 11];\n//\n//    Verts[vertexIndex].color = color;\n//    Verts[vertexIndex + 1].color = color;\n//    Verts[vertexIndex + 2].color = color;\n//    Verts[vertexIndex + 3].color = color;\n//\n//    Verts[vertexIndex].overlayColor = overlayColor;\n//    Verts[vertexIndex + 1].overlayColor = overlayColor;\n//    Verts[vertexIndex + 2].overlayColor = overlayColor;\n//    Verts[vertexIndex + 3].overlayColor = overlayColor;\n//\n//    Verts[vertexIndex].normal[0] = normals[vertexOffset];\n//    Verts[vertexIndex].normal[1] = normals[vertexOffset + 1];\n//    Verts[vertexIndex].normal[2] = normals[vertexOffset + 2];\n//    Verts[vertexIndex + 1].normal[0] = normals[vertexOffset + 3];\n//    Verts[vertexIndex + 1].normal[1] = normals[vertexOffset + 4];\n//    Verts[vertexIndex + 1].normal[2] = normals[vertexOffset + 5];\n//    Verts[vertexIndex + 2].normal[0] = normals[vertexOffset + 6];\n//    Verts[vertexIndex + 2].normal[1] = normals[vertexOffset + 7];\n//    Verts[vertexIndex + 2].normal[2] = normals[vertexOffset + 8];\n//    Verts[vertexIndex + 3].normal[0] = normals[vertexOffset + 9];\n//    Verts[vertexIndex + 3].normal[1] = normals[vertexOffset + 10];\n//    Verts[vertexIndex + 3].normal[2] = normals[vertexOffset + 11];\n//\n//    Verts[vertexIndex].lampColor = lampColor;\n//    Verts[vertexIndex + 1].lampColor = lampColor;\n//    Verts[vertexIndex + 2].lampColor = lampColor;\n//    Verts[vertexIndex + 3].lampColor = lampColor;\n//\n//\n//    Verts[vertexIndex].sunlight = sunlight;\n//    Verts[vertexIndex + 1].sunlight = sunlight;\n//    Verts[vertexIndex + 2].sunlight = sunlight;\n//    Verts[vertexIndex + 3].sunlight = sunlight;\n//\n//    Verts[vertexIndex].merge = 0;\n//    Verts[vertexIndex + 1].merge = 0;\n//    Verts[vertexIndex + 2].merge = 0;\n//    Verts[vertexIndex + 3].merge = 0;\n//\n//    if (waveEffect == 2){\n//        Verts[vertexIndex].waveEffect = 255;\n//        Verts[vertexIndex + 1].waveEffect = 255;\n//        Verts[vertexIndex + 2].waveEffect = 255;\n//        Verts[vertexIndex + 3].waveEffect = 255;\n//    } else if (waveEffect == 1){\n//        Verts[vertexIndex].waveEffect = 255;\n//        Verts[vertexIndex + 1].waveEffect = 0;\n//        Verts[vertexIndex + 2].waveEffect = 0;\n//        Verts[vertexIndex + 3].waveEffect = 255;\n//    } else{\n//        Verts[vertexIndex].waveEffect = 0;\n//        Verts[vertexIndex + 1].waveEffect = 0;\n//        Verts[vertexIndex + 2].waveEffect = 0;\n//        Verts[vertexIndex + 3].waveEffect = 0;\n//    }\n//\n//#define UV_0 128\n//#define UV_1 129\n//\n//    Verts[vertexIndex].tex[0] = UV_0;\n//    Verts[vertexIndex].tex[1] = UV_1;\n//    Verts[vertexIndex + 1].tex[0] = UV_0;\n//    Verts[vertexIndex + 1].tex[1] = UV_0;\n//    Verts[vertexIndex + 2].tex[0] = UV_1;\n//    Verts[vertexIndex + 2].tex[1] = UV_0;\n//    Verts[vertexIndex + 3].tex[0] = UV_1;\n//    Verts[vertexIndex + 3].tex[1] = UV_1;\n//\n//    // *********** Base Texture\n//    Verts[vertexIndex].textureIndex = (GLubyte)textureIndex;\n//    Verts[vertexIndex + 1].textureIndex = (GLubyte)textureIndex;\n//    Verts[vertexIndex + 2].textureIndex = (GLubyte)textureIndex;\n//    Verts[vertexIndex + 3].textureIndex = (GLubyte)textureIndex;\n//\n//    Verts[vertexIndex].textureAtlas = (GLubyte)texAtlas;\n//    Verts[vertexIndex + 1].textureAtlas = (GLubyte)texAtlas;\n//    Verts[vertexIndex + 2].textureAtlas = (GLubyte)texAtlas;\n//    Verts[vertexIndex + 3].textureAtlas = (GLubyte)texAtlas;\n//\n//    // *********** Overlay texture\n//    Verts[vertexIndex].overlayTextureIndex = (GLubyte)overlayTex;\n//    Verts[vertexIndex + 1].overlayTextureIndex = (GLubyte)overlayTex;\n//    Verts[vertexIndex + 2].overlayTextureIndex = (GLubyte)overlayTex;\n//    Verts[vertexIndex + 3].overlayTextureIndex = (GLubyte)overlayTex;\n//\n//    Verts[vertexIndex].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n//    Verts[vertexIndex + 1].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n//    Verts[vertexIndex + 2].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n//    Verts[vertexIndex + 3].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n}\n\n\nvoid VoxelMesher::makeTransparentFace(BlockVertex *Verts VORB_UNUSED, const ui8* positions VORB_UNUSED, const i8* normals VORB_UNUSED, int vertexOffset VORB_UNUSED, int waveEffect VORB_UNUSED, i32v3& pos VORB_UNUSED, int vertexIndex VORB_UNUSED, int textureIndex VORB_UNUSED, int overlayTextureIndex VORB_UNUSED, const ColorRGB8& color VORB_UNUSED, const ColorRGB8& overlayColor VORB_UNUSED, const ui8 sunlight VORB_UNUSED, const ColorRGB8& lampColor VORB_UNUSED, const BlockTexture* texInfo VORB_UNUSED) {\n    // TODO: Do we still want this? If so, reimplement and remove VORB_UNUSED tags.\n//\n//    //get the face index so we can determine the axis alignment\n//    int faceIndex = vertexOffset / 12;\n//    //Multiply the axis by the sign bit to get the correct offset\n//    GLubyte uOffset = (GLubyte)(pos[cubeFaceAxis[faceIndex][0]] * cubeFaceAxisSign[faceIndex][0]);\n//    GLubyte vOffset = (GLubyte)(pos[cubeFaceAxis[faceIndex][1]] * cubeFaceAxisSign[faceIndex][1]);\n//\n//    // 7 per coord\n//    pos.x *= POSITION_RESOLUTION;\n//    pos.y *= POSITION_RESOLUTION;\n//    pos.z *= POSITION_RESOLUTION;\n//\n//    //Blend type. The 6 LSBs are used to encode alpha blending, add/subtract, and multiplication factors.\n//    //They are used in the shader to determine how to blend.\n//    ui8 blendMode = getBlendMode(texInfo->blendMode);\n//    \n//    Verts[vertexIndex].blendMode = blendMode;\n//    Verts[vertexIndex + 1].blendMode = blendMode;\n//    Verts[vertexIndex + 2].blendMode = blendMode;\n//    Verts[vertexIndex + 3].blendMode = blendMode;\n//\n//    GLubyte texAtlas = (GLubyte)(textureIndex / ATLAS_SIZE);\n//    textureIndex %= ATLAS_SIZE;\n//\n//    GLubyte overlayTexAtlas = (GLubyte)(overlayTextureIndex / ATLAS_SIZE);\n//    GLubyte overlayTex = (GLubyte)(overlayTextureIndex % ATLAS_SIZE);\n//\n//    Verts[vertexIndex].textureWidth = (ubyte)texInfo->base.size.x;\n//    Verts[vertexIndex].textureHeight = (ubyte)texInfo->base.size.y;\n//    Verts[vertexIndex + 1].textureWidth = (ubyte)texInfo->base.size.x;\n//    Verts[vertexIndex + 1].textureHeight = (ubyte)texInfo->base.size.y;\n//    Verts[vertexIndex + 2].textureWidth = (ubyte)texInfo->base.size.x;\n//    Verts[vertexIndex + 2].textureHeight = (ubyte)texInfo->base.size.y;\n//    Verts[vertexIndex + 3].textureWidth = (ubyte)texInfo->base.size.x;\n//    Verts[vertexIndex + 3].textureHeight = (ubyte)texInfo->base.size.y;\n//\n//    Verts[vertexIndex].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n//    Verts[vertexIndex].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n//    Verts[vertexIndex + 1].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n//    Verts[vertexIndex + 1].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n//    Verts[vertexIndex + 2].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n//    Verts[vertexIndex + 2].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n//    Verts[vertexIndex + 3].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n//    Verts[vertexIndex + 3].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n//\n//    Verts[vertexIndex].position.x = pos.x + positions[vertexOffset];\n//    Verts[vertexIndex].position.y = pos.y + positions[vertexOffset + 1];\n//    Verts[vertexIndex].position.z = pos.z + positions[vertexOffset + 2];\n//    Verts[vertexIndex + 1].position.x = pos.x + positions[vertexOffset + 3];\n//    Verts[vertexIndex + 1].position.y = pos.y + positions[vertexOffset + 4];\n//    Verts[vertexIndex + 1].position.z = pos.z + positions[vertexOffset + 5];\n//    Verts[vertexIndex + 2].position.x = pos.x + positions[vertexOffset + 6];\n//    Verts[vertexIndex + 2].position.y = pos.y + positions[vertexOffset + 7];\n//    Verts[vertexIndex + 2].position.z = pos.z + positions[vertexOffset + 8];\n//    Verts[vertexIndex + 3].position.x = pos.x + positions[vertexOffset + 9];\n//    Verts[vertexIndex + 3].position.y = pos.y + positions[vertexOffset + 10];\n//    Verts[vertexIndex + 3].position.z = pos.z + positions[vertexOffset + 11];\n//\n//    Verts[vertexIndex].color = color;\n//    Verts[vertexIndex + 1].color = color;\n//    Verts[vertexIndex + 2].color = color;\n//    Verts[vertexIndex + 3].color = color;\n//\n//    Verts[vertexIndex].overlayColor = overlayColor;\n//    Verts[vertexIndex + 1].overlayColor = overlayColor;\n//    Verts[vertexIndex + 2].overlayColor = overlayColor;\n//    Verts[vertexIndex + 3].overlayColor = overlayColor;\n//\n//    Verts[vertexIndex].normal[0] = normals[vertexOffset];\n//    Verts[vertexIndex].normal[1] = normals[vertexOffset + 1];\n//    Verts[vertexIndex].normal[2] = normals[vertexOffset + 2];\n//    Verts[vertexIndex + 1].normal[0] = normals[vertexOffset + 3];\n//    Verts[vertexIndex + 1].normal[1] = normals[vertexOffset + 4];\n//    Verts[vertexIndex + 1].normal[2] = normals[vertexOffset + 5];\n//    Verts[vertexIndex + 2].normal[0] = normals[vertexOffset + 6];\n//    Verts[vertexIndex + 2].normal[1] = normals[vertexOffset + 7];\n//    Verts[vertexIndex + 2].normal[2] = normals[vertexOffset + 8];\n//    Verts[vertexIndex + 3].normal[0] = normals[vertexOffset + 9];\n//    Verts[vertexIndex + 3].normal[1] = normals[vertexOffset + 10];\n//    Verts[vertexIndex + 3].normal[2] = normals[vertexOffset + 11];\n//\n//    Verts[vertexIndex].lampColor = lampColor;\n//    Verts[vertexIndex + 1].lampColor = lampColor;\n//    Verts[vertexIndex + 2].lampColor = lampColor;\n//    Verts[vertexIndex + 3].lampColor = lampColor;\n//\n//\n//    Verts[vertexIndex].sunlight = sunlight;\n//    Verts[vertexIndex + 1].sunlight = sunlight;\n//    Verts[vertexIndex + 2].sunlight = sunlight;\n//    Verts[vertexIndex + 3].sunlight = sunlight;\n//\n//    Verts[vertexIndex].merge = 0;\n//    Verts[vertexIndex + 1].merge = 0;\n//    Verts[vertexIndex + 2].merge = 0;\n//    Verts[vertexIndex + 3].merge = 0;\n//\n//    if (waveEffect == 2) {\n//        Verts[vertexIndex].waveEffect = 255;\n//        Verts[vertexIndex + 1].waveEffect = 255;\n//        Verts[vertexIndex + 2].waveEffect = 255;\n//        Verts[vertexIndex + 3].waveEffect = 255;\n//    } else if (waveEffect == 1) {\n//        Verts[vertexIndex].waveEffect = 255;\n//        Verts[vertexIndex + 1].waveEffect = 0;\n//        Verts[vertexIndex + 2].waveEffect = 0;\n//        Verts[vertexIndex + 3].waveEffect = 255;\n//    } else {\n//        Verts[vertexIndex].waveEffect = 0;\n//        Verts[vertexIndex + 1].waveEffect = 0;\n//        Verts[vertexIndex + 2].waveEffect = 0;\n//        Verts[vertexIndex + 3].waveEffect = 0;\n//    }\n//\n//#define UV_0 128\n//#define UV_1 129\n//\n//    Verts[vertexIndex].tex[0] = UV_0 + uOffset;\n//    Verts[vertexIndex].tex[1] = UV_1 + vOffset;\n//    Verts[vertexIndex + 1].tex[0] = UV_0 + uOffset;\n//    Verts[vertexIndex + 1].tex[1] = UV_0 + vOffset;\n//    Verts[vertexIndex + 2].tex[0] = UV_1 + uOffset;\n//    Verts[vertexIndex + 2].tex[1] = UV_0 + vOffset;\n//    Verts[vertexIndex + 3].tex[0] = UV_1 + uOffset;\n//    Verts[vertexIndex + 3].tex[1] = UV_1 + vOffset;\n//\n//    // *********** Base Texture\n//    Verts[vertexIndex].textureIndex = (GLubyte)textureIndex;\n//    Verts[vertexIndex + 1].textureIndex = (GLubyte)textureIndex;\n//    Verts[vertexIndex + 2].textureIndex = (GLubyte)textureIndex;\n//    Verts[vertexIndex + 3].textureIndex = (GLubyte)textureIndex;\n//\n//    Verts[vertexIndex].textureAtlas = (GLubyte)texAtlas;\n//    Verts[vertexIndex + 1].textureAtlas = (GLubyte)texAtlas;\n//    Verts[vertexIndex + 2].textureAtlas = (GLubyte)texAtlas;\n//    Verts[vertexIndex + 3].textureAtlas = (GLubyte)texAtlas;\n//\n//    // *********** Overlay texture\n//    Verts[vertexIndex].overlayTextureIndex = (GLubyte)overlayTex;\n//    Verts[vertexIndex + 1].overlayTextureIndex = (GLubyte)overlayTex;\n//    Verts[vertexIndex + 2].overlayTextureIndex = (GLubyte)overlayTex;\n//    Verts[vertexIndex + 3].overlayTextureIndex = (GLubyte)overlayTex;\n//\n//    Verts[vertexIndex].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n//    Verts[vertexIndex + 1].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n//    Verts[vertexIndex + 2].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n//    Verts[vertexIndex + 3].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n}\n\n\nvoid VoxelMesher::makeCubeFace(BlockVertex *Verts VORB_UNUSED, int vertexOffset VORB_UNUSED, int waveEffect VORB_UNUSED, i32v3& pos VORB_UNUSED, int vertexIndex VORB_UNUSED, int textureIndex VORB_UNUSED, int overlayTextureIndex VORB_UNUSED, const ColorRGB8& color VORB_UNUSED, const ColorRGB8& overlayColor VORB_UNUSED, GLfloat ambientOcclusion VORB_UNUSED[], const BlockTexture* texInfo VORB_UNUSED)\n{\n    // TODO: Do we still want this? If so, reimplement and remove VORB_UNUSED tags.\n\n    ////get the face index so we can determine the axis alignment\n    //int faceIndex = vertexOffset / 12;\n    ////Multiply the axis by the sign bit to get the correct offset\n    //GLubyte uOffset = (GLubyte)(pos[cubeFaceAxis[faceIndex][0]] * cubeFaceAxisSign[faceIndex][0]);\n    //GLubyte vOffset = (GLubyte)(pos[cubeFaceAxis[faceIndex][1]] * cubeFaceAxisSign[faceIndex][1]);\n\n    //const GLubyte* cverts = cubeVertices;\n\n    //// 7 per coord\n    //pos.x *= POSITION_RESOLUTION;\n    //pos.y *= POSITION_RESOLUTION;\n    //pos.z *= POSITION_RESOLUTION;\n\n    ////Blend type. The 6 LSBs are used to encode alpha blending, add/subtract, and multiplication factors.\n    ////They are used in the shader to determine how to blend.\n    //ui8 blendMode = getBlendMode(texInfo->blendMode);\n    //\n    //Verts[vertexIndex].blendMode = blendMode;\n    //Verts[vertexIndex + 1].blendMode = blendMode;\n    //Verts[vertexIndex + 2].blendMode = blendMode;\n    //Verts[vertexIndex + 3].blendMode = blendMode;\n\n    //GLubyte texAtlas = (GLubyte)(textureIndex / ATLAS_SIZE);\n    //textureIndex %= ATLAS_SIZE;\n\n    //GLubyte overlayTexAtlas = (GLubyte)(overlayTextureIndex / ATLAS_SIZE);\n    //GLubyte overlayTex = (GLubyte)(overlayTextureIndex % ATLAS_SIZE);\n\n    //Verts[vertexIndex].textureWidth = (ubyte)texInfo->base.size.x;\n    //Verts[vertexIndex].textureHeight = (ubyte)texInfo->base.size.y;\n    //Verts[vertexIndex + 1].textureWidth = (ubyte)texInfo->base.size.x;\n    //Verts[vertexIndex + 1].textureHeight = (ubyte)texInfo->base.size.y;\n    //Verts[vertexIndex + 2].textureWidth = (ubyte)texInfo->base.size.x;\n    //Verts[vertexIndex + 2].textureHeight = (ubyte)texInfo->base.size.y;\n    //Verts[vertexIndex + 3].textureWidth = (ubyte)texInfo->base.size.x;\n    //Verts[vertexIndex + 3].textureHeight = (ubyte)texInfo->base.size.y;\n\n    //Verts[vertexIndex].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n    //Verts[vertexIndex].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n    //Verts[vertexIndex + 1].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n    //Verts[vertexIndex + 1].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n    //Verts[vertexIndex + 2].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n    //Verts[vertexIndex + 2].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n    //Verts[vertexIndex + 3].overlayTextureWidth = (ubyte)texInfo->overlay.size.x;\n    //Verts[vertexIndex + 3].overlayTextureHeight = (ubyte)texInfo->overlay.size.y;\n\n    //Verts[vertexIndex].position.x = pos.x + cverts[vertexOffset];\n    //Verts[vertexIndex].position.y = pos.y + cverts[vertexOffset + 1];\n    //Verts[vertexIndex].position.z = pos.z + cverts[vertexOffset + 2];\n    //Verts[vertexIndex + 1].position.x = pos.x + cverts[vertexOffset + 3];\n    //Verts[vertexIndex + 1].position.y = pos.y + cverts[vertexOffset + 4];\n    //Verts[vertexIndex + 1].position.z = pos.z + cverts[vertexOffset + 5];\n    //Verts[vertexIndex + 2].position.x = pos.x + cverts[vertexOffset + 6];\n    //Verts[vertexIndex + 2].position.y = pos.y + cverts[vertexOffset + 7];\n    //Verts[vertexIndex + 2].position.z = pos.z + cverts[vertexOffset + 8];\n    //Verts[vertexIndex + 3].position.x = pos.x + cverts[vertexOffset + 9];\n    //Verts[vertexIndex + 3].position.y = pos.y + cverts[vertexOffset + 10];\n    //Verts[vertexIndex + 3].position.z = pos.z + cverts[vertexOffset + 11];\n\n    //Verts[vertexIndex].color.r = (GLubyte)(color.r * ambientOcclusion[0]);\n    //Verts[vertexIndex].color.g = (GLubyte)(color.g * ambientOcclusion[0]);\n    //Verts[vertexIndex].color.b = (GLubyte)(color.b * ambientOcclusion[0]);\n    //Verts[vertexIndex + 1].color.r = (GLubyte)(color.r * ambientOcclusion[1]);\n    //Verts[vertexIndex + 1].color.g = (GLubyte)(color.g * ambientOcclusion[1]);\n    //Verts[vertexIndex + 1].color.b = (GLubyte)(color.b * ambientOcclusion[1]);\n    //Verts[vertexIndex + 2].color.r = (GLubyte)(color.r * ambientOcclusion[2]);\n    //Verts[vertexIndex + 2].color.g = (GLubyte)(color.g * ambientOcclusion[2]);\n    //Verts[vertexIndex + 2].color.b = (GLubyte)(color.b * ambientOcclusion[2]);\n    //Verts[vertexIndex + 3].color.r = (GLubyte)(color.r * ambientOcclusion[3]);\n    //Verts[vertexIndex + 3].color.g = (GLubyte)(color.g * ambientOcclusion[3]);\n    //Verts[vertexIndex + 3].color.b = (GLubyte)(color.b * ambientOcclusion[3]);\n\n    //Verts[vertexIndex].overlayColor.r = (GLubyte)(overlayColor.r * ambientOcclusion[0]);\n    //Verts[vertexIndex].overlayColor.g = (GLubyte)(overlayColor.g * ambientOcclusion[0]);\n    //Verts[vertexIndex].overlayColor.b = (GLubyte)(overlayColor.b * ambientOcclusion[0]);\n    //Verts[vertexIndex + 1].overlayColor.r = (GLubyte)(overlayColor.r * ambientOcclusion[1]);\n    //Verts[vertexIndex + 1].overlayColor.g = (GLubyte)(overlayColor.g * ambientOcclusion[1]);\n    //Verts[vertexIndex + 1].overlayColor.b = (GLubyte)(overlayColor.b * ambientOcclusion[1]);\n    //Verts[vertexIndex + 2].overlayColor.r = (GLubyte)(overlayColor.r * ambientOcclusion[2]);\n    //Verts[vertexIndex + 2].overlayColor.g = (GLubyte)(overlayColor.g * ambientOcclusion[2]);\n    //Verts[vertexIndex + 2].overlayColor.b = (GLubyte)(overlayColor.b * ambientOcclusion[2]);\n    //Verts[vertexIndex + 3].overlayColor.r = (GLubyte)(overlayColor.r * ambientOcclusion[3]);\n    //Verts[vertexIndex + 3].overlayColor.g = (GLubyte)(overlayColor.g * ambientOcclusion[3]);\n    //Verts[vertexIndex + 3].overlayColor.b = (GLubyte)(overlayColor.b * ambientOcclusion[3]);\n\n    //Verts[vertexIndex].normal[0] = cubeNormals[vertexOffset];\n    //Verts[vertexIndex].normal[1] = cubeNormals[vertexOffset + 1];\n    //Verts[vertexIndex].normal[2] = cubeNormals[vertexOffset + 2];\n    //Verts[vertexIndex + 1].normal[0] = cubeNormals[vertexOffset + 3];\n    //Verts[vertexIndex + 1].normal[1] = cubeNormals[vertexOffset + 4];\n    //Verts[vertexIndex + 1].normal[2] = cubeNormals[vertexOffset + 5];\n    //Verts[vertexIndex + 2].normal[0] = cubeNormals[vertexOffset + 6];\n    //Verts[vertexIndex + 2].normal[1] = cubeNormals[vertexOffset + 7];\n    //Verts[vertexIndex + 2].normal[2] = cubeNormals[vertexOffset + 8];\n    //Verts[vertexIndex + 3].normal[0] = cubeNormals[vertexOffset + 9];\n    //Verts[vertexIndex + 3].normal[1] = cubeNormals[vertexOffset + 10];\n    //Verts[vertexIndex + 3].normal[2] = cubeNormals[vertexOffset + 11];\n\n    //Verts[vertexIndex].merge = 1;\n    //Verts[vertexIndex + 1].merge = 1;\n    //Verts[vertexIndex + 2].merge = 1;\n    //Verts[vertexIndex + 3].merge = 1;\n\n    //if (waveEffect == 2){\n    //    Verts[vertexIndex].waveEffect = 255;\n    //    Verts[vertexIndex + 1].waveEffect = 255;\n    //    Verts[vertexIndex + 2].waveEffect = 255;\n    //    Verts[vertexIndex + 3].waveEffect = 255;\n    //} else if (waveEffect == 1){\n    //    Verts[vertexIndex].waveEffect = 255;\n    //    Verts[vertexIndex + 1].waveEffect = 0;\n    //    Verts[vertexIndex + 2].waveEffect = 0;\n    //    Verts[vertexIndex + 3].waveEffect = 255;\n    //} else{\n    //    Verts[vertexIndex].waveEffect = 0;\n    //    Verts[vertexIndex + 1].waveEffect = 0;\n    //    Verts[vertexIndex + 2].waveEffect = 0;\n    //    Verts[vertexIndex + 3].waveEffect = 0;\n    //}\n\n    //#define UV_0 128\n    //#define UV_1 129\n\n    //Verts[vertexIndex].tex[0] = UV_0 + uOffset;\n    //Verts[vertexIndex].tex[1] = UV_1 + vOffset;\n    //Verts[vertexIndex + 1].tex[0] = UV_0 + uOffset;\n    //Verts[vertexIndex + 1].tex[1] = UV_0 + vOffset;\n    //Verts[vertexIndex + 2].tex[0] = UV_1 + uOffset;\n    //Verts[vertexIndex + 2].tex[1] = UV_0 + vOffset;\n    //Verts[vertexIndex + 3].tex[0] = UV_1 + uOffset;\n    //Verts[vertexIndex + 3].tex[1] = UV_1 + vOffset;\n\n    //// *********** Base Texture\n    //Verts[vertexIndex].textureIndex = (GLubyte)textureIndex;\n    //Verts[vertexIndex + 1].textureIndex = (GLubyte)textureIndex;\n    //Verts[vertexIndex + 2].textureIndex = (GLubyte)textureIndex;\n    //Verts[vertexIndex + 3].textureIndex = (GLubyte)textureIndex;\n\n    //Verts[vertexIndex].textureAtlas = (GLubyte)texAtlas;\n    //Verts[vertexIndex + 1].textureAtlas = (GLubyte)texAtlas;\n    //Verts[vertexIndex + 2].textureAtlas = (GLubyte)texAtlas;\n    //Verts[vertexIndex + 3].textureAtlas = (GLubyte)texAtlas;\n\n    //// *********** Overlay texture\n    //Verts[vertexIndex].overlayTextureIndex = (GLubyte)overlayTex;\n    //Verts[vertexIndex + 1].overlayTextureIndex = (GLubyte)overlayTex;\n    //Verts[vertexIndex + 2].overlayTextureIndex = (GLubyte)overlayTex;\n    //Verts[vertexIndex + 3].overlayTextureIndex = (GLubyte)overlayTex;\n\n    //Verts[vertexIndex].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n    //Verts[vertexIndex + 1].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n    //Verts[vertexIndex + 2].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n    //Verts[vertexIndex + 3].overlayTextureAtlas = (GLubyte)overlayTexAtlas;\n}\n\nconst GLubyte waterUVs[8] = { 0, 7, 0, 0, 7, 0, 7, 7 };\n\nvoid VoxelMesher::makeLiquidFace(std::vector<LiquidVertex>& verts, i32 index, ui8 uOff, ui8 vOff, const ColorRGB8& lampColor, ui8 sunlight, const ColorRGB8& color, ui8 textureUnit) {\n\n    verts.resize(verts.size() + 4);\n    verts[index].tex[0] = waterUVs[0] + uOff;\n    verts[index].tex[1] = waterUVs[1] + vOff;\n    verts[index + 1].tex[0] = waterUVs[2] + uOff;\n    verts[index + 1].tex[1] = waterUVs[3] + vOff;\n    verts[index + 2].tex[0] = waterUVs[4] + uOff;\n    verts[index + 2].tex[1] = waterUVs[5] + vOff;\n    verts[index + 3].tex[0] = waterUVs[6] + uOff;\n    verts[index + 3].tex[1] = waterUVs[7] + vOff;\n\n    verts[index].lampColor = lampColor;\n    verts[index + 1].lampColor = lampColor;\n    verts[index + 2].lampColor = lampColor;\n    verts[index + 3].lampColor = lampColor;\n\n    verts[index].sunlight = sunlight;\n    verts[index + 1].sunlight = sunlight;\n    verts[index + 2].sunlight = sunlight;\n    verts[index + 3].sunlight = sunlight;\n\n    verts[index].color.r = color.r;\n    verts[index].color.g = color.g;\n    verts[index].color.b = color.b;\n    verts[index + 1].color.r = color.r;\n    verts[index + 1].color.g = color.g;\n    verts[index + 1].color.b = color.b;\n    verts[index + 2].color.r = color.r;\n    verts[index + 2].color.g = color.g;\n    verts[index + 2].color.b = color.b;\n    verts[index + 3].color.r = color.r;\n    verts[index + 3].color.g = color.g;\n    verts[index + 3].color.b = color.b;\n\n    verts[index].textureUnit = (GLubyte)textureUnit;\n    verts[index + 1].textureUnit = (GLubyte)textureUnit;\n    verts[index + 2].textureUnit = (GLubyte)textureUnit;\n    verts[index + 3].textureUnit = (GLubyte)textureUnit;\n}\n\nvoid VoxelMesher::makePhysicsBlockFace(std::vector <PhysicsBlockVertex> &verts VORB_UNUSED, int vertexOffset VORB_UNUSED, int &index VORB_UNUSED, const BlockTexture& blockTexture VORB_UNUSED)\n{\n    // TODO: Do we still want this? If so, reimplement and remove VORB_UNUSED tags.\n\n    /*  ui8 textureAtlas = (ui8)(blockTexture.base.index / ATLAS_SIZE);\n      ui8 textureIndex = (ui8)(blockTexture.base.index % ATLAS_SIZE);\n\n      ui8 overlayTextureAtlas = (ui8)(blockTexture.overlay.index / ATLAS_SIZE);\n      ui8 overlayTextureIndex = (ui8)(blockTexture.overlay.index % ATLAS_SIZE);\n\n      ui8 blendMode = getBlendMode(blockTexture.blendMode);\n\n      const GLubyte* cverts = cubeVertices;\n\n      verts[index].blendMode = blendMode;\n      verts[index + 1].blendMode = blendMode;\n      verts[index + 2].blendMode = blendMode;\n      verts[index + 3].blendMode = blendMode;\n      verts[index + 4].blendMode = blendMode;\n      verts[index + 5].blendMode = blendMode;\n\n      verts[index].textureWidth = (ui8)blockTexture.base.size.x;\n      verts[index].textureHeight = (ui8)blockTexture.base.size.y;\n      verts[index + 1].textureWidth = (ui8)blockTexture.base.size.x;\n      verts[index + 1].textureHeight = (ui8)blockTexture.base.size.y;\n      verts[index + 2].textureWidth = (ui8)blockTexture.base.size.x;\n      verts[index + 2].textureHeight = (ui8)blockTexture.base.size.y;\n      verts[index + 3].textureWidth = (ui8)blockTexture.base.size.x;\n      verts[index + 3].textureHeight = (ui8)blockTexture.base.size.y;\n      verts[index + 4].textureWidth = (ui8)blockTexture.base.size.x;\n      verts[index + 4].textureHeight = (ui8)blockTexture.base.size.y;\n      verts[index + 5].textureWidth = (ui8)blockTexture.base.size.x;\n      verts[index + 5].textureHeight = (ui8)blockTexture.base.size.y;\n\n      verts[index].overlayTextureWidth = (ui8)blockTexture.overlay.size.x;\n      verts[index].overlayTextureHeight = (ui8)blockTexture.overlay.size.y;\n      verts[index + 1].overlayTextureWidth = (ui8)blockTexture.overlay.size.x;\n      verts[index + 1].overlayTextureHeight = (ui8)blockTexture.overlay.size.y;\n      verts[index + 2].overlayTextureWidth = (ui8)blockTexture.overlay.size.x;\n      verts[index + 2].overlayTextureHeight = (ui8)blockTexture.overlay.size.y;\n      verts[index + 3].overlayTextureWidth = (ui8)blockTexture.overlay.size.x;\n      verts[index + 3].overlayTextureHeight = (ui8)blockTexture.overlay.size.y;\n      verts[index + 4].overlayTextureWidth = (ui8)blockTexture.overlay.size.x;\n      verts[index + 4].overlayTextureHeight = (ui8)blockTexture.overlay.size.y;\n      verts[index + 5].overlayTextureWidth = (ui8)blockTexture.overlay.size.x;\n      verts[index + 5].overlayTextureHeight = (ui8)blockTexture.overlay.size.y;\n\n      verts[index].normal[0] = cubeNormals[vertexOffset];\n      verts[index].normal[1] = cubeNormals[vertexOffset + 1];\n      verts[index].normal[2] = cubeNormals[vertexOffset + 2];\n      verts[index + 1].normal[0] = cubeNormals[vertexOffset + 3];\n      verts[index + 1].normal[1] = cubeNormals[vertexOffset + 4];\n      verts[index + 1].normal[2] = cubeNormals[vertexOffset + 5];\n      verts[index + 2].normal[0] = cubeNormals[vertexOffset + 6];\n      verts[index + 2].normal[1] = cubeNormals[vertexOffset + 7];\n      verts[index + 2].normal[2] = cubeNormals[vertexOffset + 8];\n      verts[index + 3].normal[0] = cubeNormals[vertexOffset + 6];\n      verts[index + 3].normal[1] = cubeNormals[vertexOffset + 7];\n      verts[index + 3].normal[2] = cubeNormals[vertexOffset + 8];\n      verts[index + 4].normal[0] = cubeNormals[vertexOffset + 9];\n      verts[index + 4].normal[1] = cubeNormals[vertexOffset + 10];\n      verts[index + 4].normal[2] = cubeNormals[vertexOffset + 11];\n      verts[index + 5].normal[0] = cubeNormals[vertexOffset];\n      verts[index + 5].normal[1] = cubeNormals[vertexOffset + 1];\n      verts[index + 5].normal[2] = cubeNormals[vertexOffset + 2];\n\n      verts[index].position[0] = cverts[vertexOffset];\n      verts[index].position[1] = cverts[vertexOffset + 1];\n      verts[index].position[2] = cverts[vertexOffset + 2];\n      verts[index + 1].position[0] = cverts[vertexOffset + 3];\n      verts[index + 1].position[1] = cverts[vertexOffset + 4];\n      verts[index + 1].position[2] = cverts[vertexOffset + 5];\n      verts[index + 2].position[0] = cverts[vertexOffset + 6];\n      verts[index + 2].position[1] = cverts[vertexOffset + 7];\n      verts[index + 2].position[2] = cverts[vertexOffset + 8];\n      verts[index + 3].position[0] = cverts[vertexOffset + 6];\n      verts[index + 3].position[1] = cverts[vertexOffset + 7];\n      verts[index + 3].position[2] = cverts[vertexOffset + 8];\n      verts[index + 4].position[0] = cverts[vertexOffset + 9];\n      verts[index + 4].position[1] = cverts[vertexOffset + 10];\n      verts[index + 4].position[2] = cverts[vertexOffset + 11];\n      verts[index + 5].position[0] = cverts[vertexOffset];\n      verts[index + 5].position[1] = cverts[vertexOffset + 1];\n      verts[index + 5].position[2] = cverts[vertexOffset + 2];\n\n      #define UV_0 128\n      #define UV_1 129\n\n      verts[index].tex[0] = UV_0;\n      verts[index].tex[1] = UV_1;\n      verts[index + 1].tex[0] = UV_0;\n      verts[index + 1].tex[1] = UV_0;\n      verts[index + 2].tex[0] = UV_1;\n      verts[index + 2].tex[1] = UV_0;\n      verts[index + 3].tex[0] = UV_1;\n      verts[index + 3].tex[1] = UV_0;\n      verts[index + 4].tex[0] = UV_1;\n      verts[index + 4].tex[1] = UV_1;\n      verts[index + 5].tex[0] = UV_0;\n      verts[index + 5].tex[1] = UV_1;\n\n      verts[index].textureAtlas = textureAtlas;\n      verts[index + 1].textureAtlas = textureAtlas;\n      verts[index + 2].textureAtlas = textureAtlas;\n      verts[index + 3].textureAtlas = textureAtlas;\n      verts[index + 4].textureAtlas = textureAtlas;\n      verts[index + 5].textureAtlas = textureAtlas;\n\n      verts[index].textureIndex = textureIndex;\n      verts[index + 1].textureIndex = textureIndex;\n      verts[index + 2].textureIndex = textureIndex;\n      verts[index + 3].textureIndex = textureIndex;\n      verts[index + 4].textureIndex = textureIndex;\n      verts[index + 5].textureIndex = textureIndex;\n\n      verts[index].overlayTextureAtlas = overlayTextureAtlas;\n      verts[index + 1].overlayTextureAtlas = overlayTextureAtlas;\n      verts[index + 2].overlayTextureAtlas = overlayTextureAtlas;\n      verts[index + 3].overlayTextureAtlas = overlayTextureAtlas;\n      verts[index + 4].overlayTextureAtlas = overlayTextureAtlas;\n      verts[index + 5].overlayTextureAtlas = overlayTextureAtlas;\n\n      verts[index].overlayTextureIndex = overlayTextureIndex;\n      verts[index + 1].overlayTextureIndex = overlayTextureIndex;\n      verts[index + 2].overlayTextureIndex = overlayTextureIndex;\n      verts[index + 3].overlayTextureIndex = overlayTextureIndex;\n      verts[index + 4].overlayTextureIndex = overlayTextureIndex;\n      verts[index + 5].overlayTextureIndex = overlayTextureIndex;*/\n\n}\n\nui8 VoxelMesher::getBlendMode(const BlendType& blendType) {\n    ubyte blendMode = 0x14; //0x14 = 00 01 01 00\n    switch (blendType) {\n        case BlendType::ALPHA:\n            blendMode |= 1; //Sets blendMode to 00 01 01 01\n            break;\n        case BlendType::ADD:\n            blendMode += 4; //Sets blendMode to 00 01 10 00\n            break;\n        case BlendType::SUBTRACT:\n            blendMode -= 4; //Sets blendMode to 00 01 00 00\n            break;\n        case BlendType::MULTIPLY:\n            blendMode -= 16; //Sets blendMode to 00 00 01 00\n            break;\n    }\n    return blendMode;\n}"
  },
  {
    "path": "SoA/VoxelMesher.h",
    "content": "#pragma once\n#include \"BlockData.h\"\n#include \"Vertex.h\"\n\n#define NUM_FLORA_MESHES 4\n#define NUM_FLORA_VERTICES 36\n\n#define NUM_CROSSFLORA_MESHES 2\n#define NUM_CROSSFLORA_VERTICES 24\n\n// Offsets into CubeVertices\n#define CUBE_FACE_0_VERTEX_OFFSET 0\n#define CUBE_FACE_1_VERTEX_OFFSET 12\n#define CUBE_FACE_2_VERTEX_OFFSET 24\n#define CUBE_FACE_3_VERTEX_OFFSET 36\n#define CUBE_FACE_4_VERTEX_OFFSET 48\n#define CUBE_FACE_5_VERTEX_OFFSET 60\n\n//Provides helpful meshing functions for voxels\nclass VoxelMesher\n{\npublic:\n    static void makeFloraFace(BlockVertex *Verts, const ui8* positions, const i8* normals, int vertexOffset, int waveEffect, i32v3& pos, int vertexIndex, int textureIndex, int overlayTextureIndex, const ColorRGB8& color, const ColorRGB8& overlayColor, const ui8 sunlight, const ColorRGB8& lampColor, const BlockTexture* texInfo);\n    static void makeTransparentFace(BlockVertex *Verts, const ui8* positions, const i8* normals, int vertexOffset, int waveEffect, i32v3& pos, int vertexIndex, int textureIndex, int overlayTextureIndex, const ColorRGB8& color, const ColorRGB8& overlayColor, const ui8 sunlight, const ColorRGB8& lampColor, const BlockTexture* texInfo);\n    static void makeCubeFace(BlockVertex *Verts, int vertexOffset, int waveEffect, i32v3& pos, int vertexIndex, int textureIndex, int overlayTextureIndex, const ColorRGB8& color, const ColorRGB8& overlayColor, GLfloat ambientOcclusion[], const BlockTexture* texInfo);\n    static void makeLiquidFace(std::vector<LiquidVertex>& verts, i32 index, ui8 uOff, ui8 vOff, const ColorRGB8& lampColor, ui8 sunlight, const ColorRGB8& color, ui8 textureUnit);\n    static void makePhysicsBlockFace(std::vector <PhysicsBlockVertex> &verts, int vertexOffset, int &index, const BlockTexture& blockTexture);\n    static ui8 getBlendMode(const BlendType& blendType);\n#define POSITION_RESOLUTION 7\n#define ATLAS_SIZE 256\n#define ATLAS_MODULUS_BITS 0xFF\n\n#define NUM_FACES 6\n#define NUM_VERTICES 72\n\n    static const ui8v3 VOXEL_POSITIONS[NUM_FACES][4];\n    static const GLfloat leafVertices[NUM_VERTICES];\n    static const int cubeFaceAxis[NUM_FACES][2];\n    static const int cubeFaceAxisSign[NUM_FACES][2];\n    static const GLfloat liquidVertices[NUM_VERTICES];\n    static const GLfloat waterCubeVertices[NUM_VERTICES];\n    static const GLbyte cubeNormals[NUM_VERTICES];\n    static const GLbyte floraNormals[NUM_VERTICES];\n    static const ui8v3 floraVertices[NUM_FLORA_MESHES][12];\n    static const ui8v3 crossFloraVertices[NUM_CROSSFLORA_MESHES][8];\n};\n\n"
  },
  {
    "path": "SoA/VoxelModel.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelModel.h\"\n\n#include \"VoxelMatrix.h\"\n#include \"VoxelModelLoader.h\"\n#include \"ModelMesher.h\"\n\nVoxelModel::VoxelModel():\nm_mesh() {\n    // Empty\n}\n\nVoxelModel::~VoxelModel() {\n    m_matrix.dispose();\n}\n\nbool VoxelModel::loadFromFile(const nString& path) {\n    VoxelMatrix matrix;\n    if (!VoxelModelLoader::loadModel(path, matrix)) {\n        return false;\n    }\n    setMatrix(matrix);\n    return true;\n}\n"
  },
  {
    "path": "SoA/VoxelModel.h",
    "content": "#pragma once\n#ifndef VoxelModel_h__\n#define VoxelModel_h__\n\n#include <vector>\n\n#include <Vorb/graphics/GLProgram.h>\n#include <Vorb/ui/IGameScreen.h>\n\n#include \"VoxelModelMesh.h\"\n#include \"VoxelMatrix.h\"\n\nclass VoxelModelVertex;\n\nclass VoxelModel {\npublic:\n    VoxelModel();\n    ~VoxelModel();\n    \n    bool loadFromFile(const nString& path);\n    \n    void setMatrix(const VoxelMatrix& matrix) { m_matrix = matrix; }\n    void setMesh(const VoxelModelMesh& mesh) { m_mesh = mesh; }\n    \n    VoxelMatrix& getMatrix() { return m_matrix; }\n    const VoxelMatrix& getMatrix() const { return m_matrix; }\n    const VoxelModelMesh& getMesh() const { return m_mesh; }\n\nprivate:\n    VoxelMatrix m_matrix;\n    VoxelModelMesh m_mesh;\n};\n\n#endif //VoxelModel_h__"
  },
  {
    "path": "SoA/VoxelModelLoader.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelModelLoader.h\"\n\n#include <iostream>\n#include <fstream>\n\n#include \"VoxelMatrix.h\"\n\nVoxelModelLoader::VoxelModelLoader() {\n    //Empty\n}\n\n    \nbool VoxelModelLoader::loadModel(const nString& filePath,\n    VoxelMatrix& matrix /* Even though .qb can have multiple matrices, we assume a single matrix. */) {\n    FILE* file = NULL;\n    file=fopen( filePath.c_str(), \"rb\");\n\n    bool ok = true;\n    ui8* version = new ui8[4];\n    ok = fread(&version[0], sizeof(char)*4, 1, file) == 1;\n    ui32 colorFormat;\n    ok = fread(&colorFormat, sizeof(ui32), 1, file) == 1;\n    ui32 zAxisOrientation;\n    ok = fread(&zAxisOrientation, sizeof(ui32), 1, file) == 1;\n    ui32 compressed;\n    ok = fread(&compressed, sizeof(ui32), 1, file) == 1;\n    ui32 visibilityMaskEncoded;\n    ok = fread(&visibilityMaskEncoded, sizeof(ui32), 1, file) == 1;\n    ui32 numMatrices;\n    ok = fread(&numMatrices, sizeof(ui32), 1, file) == 1;\n\n    char nameLength = 0;\n    ok = fread((char*)&nameLength, sizeof(char), 1, file) == 1;\n    char* name = new char[nameLength + 1];\n    ok = fread(name, sizeof(char)*nameLength, 1, file) == 1;\n    name[(size_t)nameLength] = 0;\n    printf(\"%s\", name);\n\n    ok = fread(&matrix.size.x, sizeof(ui32), 1, file) == 1;\n    ok = fread(&matrix.size.y, sizeof(ui32), 1, file) == 1;\n    ok = fread(&matrix.size.z, sizeof(ui32), 1, file) == 1;\n\n    ok = fread(&matrix.position.x, sizeof(ui32), 1, file) == 1;\n    ok = fread(&matrix.position.y, sizeof(ui32), 1, file) == 1;\n    ok = fread(&matrix.position.z, sizeof(ui32), 1, file) == 1;\n\n    matrix.data = new ColorRGBA8[matrix.size.x * matrix.size.y * matrix.size.z];\n\n    if(compressed == 0) { // Uncompressed Data\n        for(ui32 z = 0; z < matrix.size.z; z++) {\n            for(ui32 y = 0; y < matrix.size.y; y++) {\n                for(ui32 x = 0; x < matrix.size.x; x++) {\n                    ui32 data = 0;\n                    ok = fread(&data, sizeof(ui32), 1, file) == 1;\n                    ui32 r = data & 0x000000ff;\n                    ui32 g = (data & 0x0000ff00) >> 8;\n                    ui32 b = (data & 0x00ff0000) >> 16;\n                    ui32 a = (data & 0xff000000) >> 24;\n                    int location = matrix.getIndex(x, y, z);\n                    matrix.data[location] = ColorRGBA8(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);\n                }\n            }\n        }\n    } else { // RLE compressed\n        ui32 z = 0;\n        while(z < matrix.size.z) {\n            ui32 index = 0;\n            while(true) {\n                ui32 data = 0;\n                ok = fread(&data, sizeof(ui32), 1, file) == 1;\n                if(data == NEXT_SLICE_FLAG) {\n                    break;\n                } else if(data == CODE_FLAG) {\n                    ui32 count = 0;\n                    ok = fread(&count, sizeof(ui32), 1, file) == 1;\n                    ok = fread(&data, sizeof(ui32), 1, file) == 1;\n                    for(ui32 j = 0; j < count; j++) {\n                        i32 x = index % matrix.size.x;\n                        i32 y = index / matrix.size.x;\n                        index++;\n                        ui32 r = data & 0x000000ff;\n                        ui32 g = (data & 0x0000ff00) >> 8;\n                        ui32 b = (data & 0x00ff0000) >> 16;\n                        ui32 a = (data & 0xff000000) >> 24;\n                        int location = matrix.getIndex(x, y, z);\n                        matrix.data[location] = ColorRGBA8(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);\n                    }\n                } else {\n                    i32 x = index % matrix.size.x;\n                    i32 y = index / matrix.size.x;\n                    index++;\n                    ui32 r = data & 0x000000ff;\n                    ui32 g = (data & 0x0000ff00) >> 8;\n                    ui32 b = (data & 0x00ff0000) >> 16;\n                    ui32 a = (data & 0xff000000) >> 24;\n                    int location = matrix.getIndex(x, y, z);\n                    matrix.data[location] = ColorRGBA8(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);\n                }\n            }\n            z++;\n        }\n    }\n    \n    return ok;\n}"
  },
  {
    "path": "SoA/VoxelModelLoader.h",
    "content": "///\n/// VoxelModelLoader.h\n/// Seed of Andromeda\n///\n/// Created by Frank McCoy on 7 April 2015\n/// Copyright 2014-2015 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Class to handle loading of VoxelModels.\n/// Currently supports the Qubicle binary format.\n///\n\n#pragma once\n\n#ifndef VoxelModelLoader_h__\n#define VoxelModelLoader_h__\n\n#include <Vorb/colors.h>\n\n#include <vector>\n\n#define CODE_FLAG 2\n#define NEXT_SLICE_FLAG 6\n\nclass VoxelMatrix;\n\nclass VoxelModelLoader {\npublic:\n    static bool loadModel(const nString& filePath, VoxelMatrix& matrix);\nprivate:\n    VoxelModelLoader();\n};\n\n#endif // VoxelModelLoader_h__"
  },
  {
    "path": "SoA/VoxelModelMesh.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelModelMesh.h\"\n\nvoid VoxelModelMesh::bind() const {\n    glBindVertexArray(m_vao);\n    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo);\n}\n\nvoid VoxelModelMesh::unbind() {\n    glBindVertexArray(0);\n}\n\nvoid VoxelModelMesh::dispose() {\n    if (m_vbo) {\n        glDeleteBuffers(1, &m_vbo);\n        m_vbo = 0;\n    }\n    if (m_ibo) {\n        glDeleteBuffers(1, &m_ibo);\n        m_ibo = 0;\n    }\n    if (m_vao) {\n        glDeleteVertexArrays(1, &m_vao);\n        m_vao = 0;\n    }\n}"
  },
  {
    "path": "SoA/VoxelModelMesh.h",
    "content": "#pragma once\n#ifndef VoxelModelMesh_h__\n#define VoxelModelMesh_h__\n\n#include <Vorb/types.h>\n#include <Vorb/graphics/gtypes.h>\n\nclass VoxelModelVertex {\npublic:\n    VoxelModelVertex() {}\n    VoxelModelVertex(f32v3 pos, color3 color, f32v3 normal):\n        pos(pos),\n        normal(normal),\n        color(color) {}\n    f32v3 pos;\n    f32v3 normal;\n    color3 color;\n    ui8 padding;\n};\n\nclass VoxelModelMesh {\n    friend class ModelMesher;\npublic:\n    void bind() const;\n    static void unbind();\n\n    void dispose();\n\n    VGVertexBuffer getVBO() const { return m_vbo; }\n    VGIndexBuffer getIBO() const { return m_ibo; }\n    VGVertexArray getVAO() const { return m_vao; }\n    ui32 getIndexCount() const { return m_indCount; }\n    ui32 getTriCount() const { return m_triCount; }\nprivate:\n    VGVertexBuffer m_vbo = 0;\n    VGIndexBuffer m_ibo = 0;\n    VGVertexArray m_vao = 0;\n    ui32 m_indCount = 0;\n    ui32 m_triCount = 0;\n};\n\n#endif // VoxelModelMesh_h__"
  },
  {
    "path": "SoA/VoxelModelRenderer.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelModelRenderer.h\"\n#include \"ShaderLoader.h\"\n\n#include \"VoxelMatrix.h\"\n#include \"VoxelModel.h\"\n#include \"VoxelModelMesh.h\"\n#include \"RenderUtils.h\"\n\n#include <Vorb/types.h>\n\nvoid VoxelModelRenderer::initGL() {\n    m_program = ShaderLoader::createProgramFromFile(\"Shaders/Models/VoxelModel.vert\",\n                                                    \"Shaders/Models/VoxelModel.frag\");\n}\n\nvoid VoxelModelRenderer::dispose() {\n    if (m_program.isCreated()) m_program.dispose();\n}\n\nvoid VoxelModelRenderer::draw(VoxelModelMesh* mesh, const f32m4& mVP, const f64v3& relativePos, const f64q& orientation) {\n\n    // Convert f64q to f32q\n    f32q orientationF32;\n    orientationF32.x = (f32)orientation.x;\n    orientationF32.y = (f32)orientation.y;\n    orientationF32.z = (f32)orientation.z;\n    orientationF32.w = (f32)orientation.w;\n    // Convert to matrix\n    f32m4 rotationMatrix = glm::toMat4(orientationF32);\n    f32m4 mW(1.0);\n    setMatrixTranslation(mW, -relativePos);\n    f32m4 mWVP = mVP * mW * rotationMatrix;\n\n    m_program.use();\n    glUniformMatrix4fv(m_program.getUniform(\"unWVP\"), 1, false, &mWVP[0][0]);\n   \n    // TODO(Ben): Temporary\n    f32v3 lightDir = glm::normalize(f32v3(1.0f, 0.0f, 1.0f));\n    glUniform3fv(m_program.getUniform(\"unLightDirWorld\"), 1, &lightDir[0]);\n\n    mesh->bind();\n    m_program.enableVertexAttribArrays();\n    glVertexAttribPointer(m_program.getAttribute(\"vPosition\"), 3, GL_FLOAT, false, sizeof(VoxelModelVertex), offsetptr(VoxelModelVertex, pos));\n    glVertexAttribPointer(m_program.getAttribute(\"vNormal\"), 3, GL_FLOAT, false, sizeof(VoxelModelVertex), offsetptr(VoxelModelVertex, normal));\n    glVertexAttribPointer(m_program.getAttribute(\"vColor\"), 3, GL_UNSIGNED_BYTE, true, sizeof(VoxelModelVertex), offsetptr(VoxelModelVertex, color));\n    \n    if (mesh->getIndexCount() == 0) {\n        glDrawArrays(GL_TRIANGLES, 0, mesh->getTriCount() * 3);\n    } else {\n        glDrawElements(GL_TRIANGLES, mesh->getIndexCount(), GL_UNSIGNED_INT, nullptr);\n    }\n    mesh->unbind();\n\n    m_program.unuse();\n}"
  },
  {
    "path": "SoA/VoxelModelRenderer.h",
    "content": "#pragma once\n#ifndef VoxelModelRenderer_h__\n#define VoxelModelRenderer_h__\n\n#include \"Vorb/graphics/GLProgram.h\"\n\nclass VoxelMatrix;\nclass VoxelModelMesh;\n\nclass VoxelModelRenderer {\npublic:\n    void initGL();\n    void dispose();\n    void draw(VoxelModelMesh* mesh, const f32m4& mVP, const f64v3& relativePos, const f64q& orientation);\nprivate:\n    vg::GLProgram m_program;\n};\n\n#endif //VoxelModelRenderer_h__"
  },
  {
    "path": "SoA/VoxelNavigation.inl",
    "content": "///\n/// VoxelNavigation.inl\n/// Vorb\n///\n/// Created by Benjamin Arnold on 26 Nov 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// This file implements the Voxel Navigation functions with\n/// thread safety.\n///\n\n#pragma once\n\n#ifndef VoxelNavigation_inl__\n#define VoxelNavigation_inl__\n\n// TODO(Ben): Generalize Chunk and voxel stuff\n// TODO(Cristian): Try to tell Ben that we can't quite generalize everything...\n#include \"Chunk.h\"\n#include \"VoxelUtils.h\"\n\nnamespace vorb {\n    namespace voxel {\n\n    //    /// Locks a chunk and unlocks the currently locked chunk. Keeps track\n    //    /// of which chunk is locked.\n    //    /// @param chunkToLock: Chunk that needs to be locked\n    //    /// @param lockedChunk: Currently locked chunk, or nullptr if no chunk\n    //    /// is locked. Will be set to chunkToLock if chunkToLock is locked.\n    //    inline void swapLockedChunk(NChunk* chunkToLock, NChunk*& lockedChunk) {\n    //        if (chunkToLock == lockedChunk) return;\n    //        if (lockedChunk) lockedChunk->unlock();\n    //        lockedChunk = chunkToLock;\n    //        lockedChunk->lock();\n    //    }\n    //    \n    //    /// Gets the blockData to the left of the input block. Owner and index are stored.\n    //    inline int getLeftBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int x, int& nextBlockIndex, NChunk*& owner) {\n    //        if (x > 0) {\n    //            owner = chunk;\n    //            nextBlockIndex = blockIndex - 1;\n    //            return chunk->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        } else if (chunk->left && chunk->left->isAccessible) {\n    //            owner = chunk->left;\n    //            nextBlockIndex = blockIndex + CHUNK_WIDTH - 1;\n    //            return owner->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the left of the input block. Owner and index are stored.\n    //    inline int getLeftBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int& nextBlockIndex, NChunk*& owner) {\n    //        return getLeftBlockData(chunk, lockedChunk, blockIndex, getXFromBlockIndex(blockIndex), nextBlockIndex, owner);\n    //    }\n\n    //    /// Gets the blockData to the left of the input block.\n    //    inline int getLeftBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex) {\n    //        if (getXFromBlockIndex(blockIndex) > 0) {\n    //            return chunk->getBlockDataSafe(lockedChunk, blockIndex - 1);\n    //        } else if (chunk->left && chunk->left->isAccessible) {\n    //            return chunk->left->getBlockDataSafe(lockedChunk, blockIndex + CHUNK_WIDTH - 1);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the right of the input block. Owner and index are stored.\n    //    inline int getRightBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int x, int& nextBlockIndex, NChunk*& owner) {\n    //        if (x < CHUNK_WIDTH - 1) {\n    //            owner = chunk;\n    //            nextBlockIndex = blockIndex + 1;\n    //            return chunk->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        } else if (chunk->right && chunk->right->isAccessible) {\n    //            owner = chunk->right;\n    //            nextBlockIndex = blockIndex - CHUNK_WIDTH + 1;\n    //            return owner->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the right of the input block. Owner and index are stored.\n    //    inline int getRightBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int& nextBlockIndex, NChunk*& owner) {\n    //        return getRightBlockData(chunk, lockedChunk, blockIndex, getXFromBlockIndex(blockIndex), nextBlockIndex, owner);\n    //    }\n\n    //    /// Gets the blockData to the right of the input block.\n    //    inline int getRightBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex) {\n    //        if (getXFromBlockIndex(blockIndex) < CHUNK_WIDTH - 1) {\n    //            return chunk->getBlockDataSafe(lockedChunk, blockIndex + 1);\n    //        } else if (chunk->right && chunk->right->isAccessible) {\n    //            return chunk->right->getBlockDataSafe(lockedChunk, blockIndex - CHUNK_WIDTH + 1);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the front of the input block. Owner and index are stored.\n    //    inline int getFrontBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int z, int& nextBlockIndex, NChunk*& owner) {\n    //        if (z < CHUNK_WIDTH - 1) {\n    //            owner = chunk;\n    //            nextBlockIndex = blockIndex + CHUNK_WIDTH;\n    //            return chunk->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        } else if (chunk->front && chunk->front->isAccessible) {\n    //            owner = chunk->front;\n    //            nextBlockIndex = blockIndex - CHUNK_LAYER + CHUNK_WIDTH;\n    //            return owner->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the front of the input block. Owner and index are stored.\n    //    inline int getFrontBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int& nextBlockIndex, NChunk*& owner) {\n    //        return getFrontBlockData(chunk, lockedChunk, blockIndex, getZFromBlockIndex(blockIndex), nextBlockIndex, owner);\n    //    }\n\n    //    /// Gets the blockData to the front of the input block.\n    //    inline int getFrontBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex) {\n    //        if (getZFromBlockIndex(blockIndex) < CHUNK_WIDTH - 1) {\n    //            return chunk->getBlockDataSafe(lockedChunk, blockIndex + CHUNK_WIDTH);\n    //        } else if (chunk->front && chunk->front->isAccessible) {\n    //            return chunk->front->getBlockDataSafe(lockedChunk, blockIndex - CHUNK_LAYER + CHUNK_WIDTH);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the back of the input block. Owner and index are stored.\n    //    inline int getBackBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int z, int& nextBlockIndex, NChunk*& owner) {\n    //        if (z > 0) {\n    //            owner = chunk;\n    //            nextBlockIndex = blockIndex - CHUNK_WIDTH;\n    //            return chunk->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        } else if (chunk->back && chunk->back->isAccessible) {\n    //            owner = chunk->back;\n    //            nextBlockIndex = blockIndex + CHUNK_LAYER - CHUNK_WIDTH;\n    //            return owner->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the back of the input block. Owner and index are stored.\n    //    inline int getBackBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int& nextBlockIndex, NChunk*& owner) {\n    //        return getBackBlockData(chunk, lockedChunk, blockIndex, getZFromBlockIndex(blockIndex), nextBlockIndex, owner);\n    //    }\n\n    //    /// Gets the blockData to the back of the input block.\n    //    inline int getBackBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex) {\n    //        if (getZFromBlockIndex(blockIndex) > 0) {\n    //            return chunk->getBlockDataSafe(lockedChunk, blockIndex - CHUNK_WIDTH);\n    //        } else if (chunk->back && chunk->back->isAccessible) {\n    //            return chunk->back->getBlockDataSafe(lockedChunk, blockIndex + CHUNK_LAYER - CHUNK_WIDTH);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the bottom of the input block. Owner and index are stored.\n    //    inline int getBottomBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int y, int& nextBlockIndex, NChunk*& owner) {\n    //        if (y > 0) {\n    //            owner = chunk;\n    //            nextBlockIndex = blockIndex - CHUNK_LAYER;\n    //            return chunk->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        } else if (chunk->bottom && chunk->bottom->isAccessible) {\n    //            owner = chunk->bottom;\n    //            nextBlockIndex = blockIndex + CHUNK_SIZE - CHUNK_LAYER;\n    //            return owner->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the bottom of the input block. Owner and index are stored.\n    //    inline int getBottomBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int& nextBlockIndex, NChunk*& owner) {\n    //        return getBottomBlockData(chunk, lockedChunk, blockIndex, getYFromBlockIndex(blockIndex), nextBlockIndex, owner);\n    //    }\n\n    //    /// Gets the blockData to the bottom of the input block.\n    //    inline int getBottomBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex) {\n    //        if (getYFromBlockIndex(blockIndex) > 0) {\n    //            return chunk->getBlockDataSafe(lockedChunk, blockIndex - CHUNK_LAYER);\n    //        } else if (chunk->bottom && chunk->bottom->isAccessible) {\n    //            return chunk->bottom->getBlockDataSafe(lockedChunk, blockIndex + CHUNK_SIZE - CHUNK_LAYER);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the top of the input block. Owner and index are stored.\n    //    inline int getTopBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int y, int& nextBlockIndex, NChunk*& owner) {\n    //        if (y < CHUNK_WIDTH - 1) {\n    //            owner = chunk;\n    //            nextBlockIndex = blockIndex + CHUNK_LAYER;\n    //            return chunk->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        } else if (chunk->top && chunk->top->isAccessible) {\n    //            owner = chunk->top;\n    //            nextBlockIndex = blockIndex - CHUNK_SIZE + CHUNK_LAYER;\n    //            return owner->getBlockDataSafe(lockedChunk, nextBlockIndex);\n    //        }\n    //        return -1;\n    //    }\n\n    //    /// Gets the blockData to the top of the input block. Owner and index are stored.\n    //    inline int getTopBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex, int& nextBlockIndex, NChunk*& owner) {\n    //        return getTopBlockData(chunk, lockedChunk, blockIndex, getYFromBlockIndex(blockIndex), nextBlockIndex, owner);\n    //    }\n\n    //    /// Gets the blockData to the top of the input block.\n    //    inline int getTopBlockData(NChunk* chunk, NChunk*& lockedChunk, int blockIndex) {\n    //        if (getYFromBlockIndex(blockIndex) < CHUNK_WIDTH - 1) {\n    //            return chunk->getBlockDataSafe(lockedChunk, blockIndex + CHUNK_LAYER);\n    //        } else if (chunk->top && chunk->top->isAccessible) {\n    //            return chunk->top->getBlockDataSafe(lockedChunk, blockIndex - CHUNK_SIZE + CHUNK_LAYER);\n    //        }\n    //        return -1;\n    //    }\n    }\n}\nnamespace vvox = vorb::voxel;\n\n#endif // VoxelNavigation_inl__\n"
  },
  {
    "path": "SoA/VoxelNodeSetter.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelNodeSetter.h\"\n\n#include \"ChunkGrid.h\"\n\nvoid VoxelNodeSetter::setNodes(ChunkHandle& h, ChunkGenLevel requiredGenLevel, std::vector<VoxelToPlace>& forcedNodes, std::vector<VoxelToPlace>& condNodes) {\n    {\n        std::lock_guard<std::mutex> l(m_lckVoxelsToAdd);\n        auto it = m_handleLookup.find(h);\n        if (it != m_handleLookup.end()) {\n            VoxelNodeSetterLookupData& ld = it->second;\n            // Copy new voxels to add\n            size_t oldSize = ld.forcedNodes.size();\n            ld.forcedNodes.resize(oldSize + forcedNodes.size());\n            memcpy(&ld.forcedNodes[oldSize], forcedNodes.data(), forcedNodes.size() * sizeof(VoxelToPlace));\n            oldSize = ld.condNodes.size();\n            ld.condNodes.resize(oldSize + condNodes.size());\n            memcpy(&ld.condNodes[oldSize], condNodes.data(), condNodes.size() * sizeof(VoxelToPlace));\n            // Update required gen level if needed\n            if (m_waitingChunks[ld.waitingChunksIndex].requiredGenLevel < requiredGenLevel) {\n                m_waitingChunks[ld.waitingChunksIndex].requiredGenLevel = requiredGenLevel;\n            }\n        } else {\n            VoxelNodeSetterLookupData& ld = m_handleLookup[h];\n            ld.forcedNodes.swap(forcedNodes);\n            ld.condNodes.swap(condNodes);\n            ld.h = h.acquire();\n            ld.waitingChunksIndex = m_waitingChunks.size();\n\n            VoxelNodeSetterWaitingChunk wc;\n            wc.ch = h;\n            wc.requiredGenLevel = requiredGenLevel;\n            m_waitingChunks.push_back(std::move(wc));\n        }\n    }\n    // TODO(Ben): Faster overload?\n    grid->submitQuery(h->getChunkPosition(), requiredGenLevel, true);\n}\n\nvoid VoxelNodeSetter::update() {\n    if (m_waitingChunks.size()) {\n        std::cout << m_waitingChunks.size() << std::endl;\n    }\n    std::lock_guard<std::mutex> l(m_lckVoxelsToAdd);\n    for (int i = (int)m_waitingChunks.size() - 1; i >= 0; i--) {\n        VoxelNodeSetterWaitingChunk& v = m_waitingChunks[i];\n\n        if (v.ch->genLevel >= v.requiredGenLevel) {\n            auto it = m_handleLookup.find(v.ch);\n\n            {\n                // Send task\n                // TODO(Ben): MEMORY MANAGEMENT PROBLEM\n                VoxelNodeSetterTask* newTask = new VoxelNodeSetterTask;\n                newTask->h = it->second.h.acquire();\n                newTask->forcedNodes.swap(it->second.forcedNodes);\n                newTask->condNodes.swap(it->second.condNodes);\n                threadPool->addTask(newTask);\n            }\n           \n            it->second.h.release();\n            m_handleLookup.erase(it);\n            \n            // Copy back node for fast removal from vector\n            VoxelNodeSetterWaitingChunk& bn = m_waitingChunks.back();\n            v.ch = bn.ch;\n            v.requiredGenLevel = bn.requiredGenLevel;\n\n            // Update lookup index\n            m_handleLookup[v.ch].waitingChunksIndex = i;\n\n            m_waitingChunks.pop_back();\n        }\n    }\n}\n"
  },
  {
    "path": "SoA/VoxelNodeSetter.h",
    "content": "//\n// VoxelNodeSetter.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 9 Sep 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Waits on chunk generation queries and then sets voxels.\n//\n\n#pragma once\n\n#ifndef VoxelNodeSetter_h__\n#define VoxelNodeSetter_h__\n\n#include <vector>\n#include \"ChunkQuery.h\"\n#include \"VoxelNodeSetterTask.h\"\n\nclass ChunkHandle;\nclass ChunkGrid;\n\nstruct VoxelNodeSetterWaitingChunk {\n    Chunk* ch;\n    ChunkGenLevel requiredGenLevel;\n};\n\nstruct VoxelNodeSetterLookupData {\n    ui32 waitingChunksIndex;\n    ChunkHandle h;\n    std::vector<VoxelToPlace> forcedNodes; ///< Always added\n    std::vector<VoxelToPlace> condNodes; ///< Conditionally added\n};\n\nclass VoxelNodeSetter {\npublic:\n    // Contents of vectors may be cleared\n    void setNodes(ChunkHandle& h,\n                  ChunkGenLevel requiredGenLevel,\n                  std::vector<VoxelToPlace>& forcedNodes,\n                  std::vector<VoxelToPlace>& condNodes);\n\n    void update();\n\n    ChunkGrid* grid = nullptr;\n    vcore::ThreadPool<WorkerData>* threadPool;\nprivate:\n    std::mutex m_lckVoxelsToAdd;\n    std::vector<VoxelNodeSetterWaitingChunk> m_waitingChunks;\n    std::map<Chunk*, VoxelNodeSetterLookupData> m_handleLookup; ///< Stores handles since they fk up in vector.\n};\n\n#endif // VoxelNodeSetter_h__\n"
  },
  {
    "path": "SoA/VoxelNodeSetterTask.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelNodeSetterTask.h\"\n\n#include \"ChunkHandle.h\"\n#include \"Chunk.h\"\n\nvoid VoxelNodeSetterTask::execute(WorkerData* workerData VORB_MAYBE_UNUSED) {\n    {\n        std::lock_guard<std::mutex> l(h->dataMutex);\n        for (auto& node : forcedNodes) {\n            h->blocks.set(node.blockIndex, node.blockID);\n        }\n        for (auto& node : condNodes) {\n            // TODO(Ben): Custom condition\n            if (h->blocks.get(node.blockIndex) == 0) {\n                h->blocks.set(node.blockIndex, node.blockID);\n            }\n        }\n    }\n\n    if (h->genLevel >= GEN_DONE) h->DataChange(h);\n\n    h.release();\n}\n\nvoid VoxelNodeSetterTask::cleanup() {\n    // TODO(Ben): Better memory management.\n    delete this;\n}\n"
  },
  {
    "path": "SoA/VoxelNodeSetterTask.h",
    "content": "//\n// VoxelNodeSetterTask.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 10 Sep 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// A task for setting voxels using the threadpool.\n//\n\n#pragma once\n\n#ifndef VoxelNodeSetterTask_h__\n#define VoxelNodeSetterTask_h__\n\n#include <Vorb/IThreadPoolTask.h>\n#include \"ChunkHandle.h\"\n\nclass WorkerData;\n\nstruct VoxelToPlace {\n    VoxelToPlace() {};\n    VoxelToPlace(ui16 blockID, ui16 blockIndex) : blockID(blockID), blockIndex(blockIndex) {};\n    ui16 blockID;\n    ui16 blockIndex;\n};\n\nclass VoxelNodeSetterTask : public vcore::IThreadPoolTask<WorkerData> {\npublic:\n    // Executes the task\n    void execute(WorkerData* workerData) override;\n\n    void cleanup() override;\n\n    ChunkHandle h;\n    std::vector<VoxelToPlace> forcedNodes; ///< Always added\n    std::vector<VoxelToPlace> condNodes; ///< Conditionally added\n};\n\n#endif // VoxelNodeSetterTask_h__\n"
  },
  {
    "path": "SoA/VoxelRay.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelRay.h\"\n\n#include <float.h>\n\n#include <Vorb/utils.h>\n\ninline f64 fastFloorf(f64 x) {\n    return FastConversion<f64, f64>::floor(x);\n}\ninline f64 fastCeilf(f64 x) {\n    return FastConversion<f64, f64>::ceiling(x);\n}\n\nVoxelRay::VoxelRay(f64v3 start, f64v3 direction) {\n    _startPos = start;\n    _direction = direction;\n    _currentPos = _startPos;\n    _currentVoxelPos = i32v3(fastFloor(_startPos.x), fastFloor(_startPos.y), fastFloor(_startPos.z));\n    _currentDist = 0.0f;\n}\n\ni32v3 VoxelRay::getNextVoxelPosition() {\n    //Find All Distances To Next Voxel In Each Direction\n    f64v3 next;\n    f64v3 r;\n\n    // X-Distance\n    if (_direction.x > 0) {\n        if (_currentPos.x == (i32)_currentPos.x) next.x = _currentPos.x + 1;\n        else next.x = fastCeilf(_currentPos.x);\n        r.x = (next.x - _currentPos.x) / _direction.x;\n    } else if (_direction.x < 0) {\n        if (_currentPos.x == (i32)_currentPos.x) next.x = _currentPos.x - 1;\n        else next.x = fastFloorf(_currentPos.x);\n        r.x = (next.x - _currentPos.x) / _direction.x;\n    } else {\n        r.x = FLT_MAX;\n    }\n\n    // Y-Distance\n    if (_direction.y > 0) {\n        if (_currentPos.y == (i32)_currentPos.y) next.y = _currentPos.y + 1;\n        else next.y = fastCeilf(_currentPos.y);\n        r.y = (next.y - _currentPos.y) / _direction.y;\n    } else if (_direction.y < 0) {\n        if (_currentPos.y == (i32)_currentPos.y) next.y = _currentPos.y - 1;\n        else next.y = fastFloorf(_currentPos.y);\n        r.y = (next.y - _currentPos.y) / _direction.y;\n    } else {\n        r.y = FLT_MAX;\n    }\n\n    // Z-Distance\n    if (_direction.z > 0) {\n        if (_currentPos.z == (i32)_currentPos.z) next.z = _currentPos.z + 1;\n        else next.z = fastCeilf(_currentPos.z);\n        r.z = (next.z - _currentPos.z) / _direction.z;\n    } else if (_direction.z < 0) {\n        if (_currentPos.z == (i32)_currentPos.z) next.z = _currentPos.z - 1;\n        else next.z = fastFloorf(_currentPos.z);\n        r.z = (next.z - _currentPos.z) / _direction.z;\n    } else {\n        r.z = FLT_MAX;\n    }\n\n    // Get Minimum Movement To The Next Voxel\n    f64 rat;\n    if (r.x < r.y && r.x < r.z) {\n        // Move In The X-Direction\n        rat = r.x;\n        _currentPos += _direction * rat;\n        if (_direction.x > 0) _currentVoxelPos.x++;\n        else if (_direction.x < 0) _currentVoxelPos.x--;\n    } else if (r.y < r.z) {\n        // Move In The Y-Direction\n        rat = r.y;\n        _currentPos += _direction * rat;\n        if (_direction.y > 0) _currentVoxelPos.y++;\n        else if (_direction.y < 0) _currentVoxelPos.y--;\n    } else {\n        // Move In The Z-Direction\n        rat = r.z;\n        _currentPos += _direction * rat;\n        if (_direction.z > 0) _currentVoxelPos.z++;\n        else if (_direction.z < 0) _currentVoxelPos.z--;\n    }\n\n    // Add The Distance The Ray Has Traversed\n    _currentDist += rat;\n\n    return _currentVoxelPos;\n}\n"
  },
  {
    "path": "SoA/VoxelRay.h",
    "content": "#pragma once\n\n#include <Vorb/types.h>\n\n// Traverses The Endless Space Of Local Voxels\nclass VoxelRay {\npublic:\n    // Create A Ray At The Starting Local Position With A Normalized Direction\n    VoxelRay(f64v3 start, f64v3 direction);\n\n    // Traverse To The Next Voxel And Return The Local Coordinates (Grid Offset)\n    i32v3 getNextVoxelPosition();\n\n    // Access The Origin Values\n    const f64v3& getStartPosition() const {\n        return _startPos;\n    }\n    const f64v3& getDirection() const {\n        return _direction;\n    }\n\n    // The Total Distance The Ray Has Traversed\n    const f64& getDistanceTraversed() const {\n        return _currentDist;\n    }\nprivate:\n    // Initialization Values\n    f64v3 _startPos;\n    f64v3 _direction;\n\n    // The Current Traversal Information\n    f64 _currentDist;\n    f64v3 _currentPos;\n\n    // The Offset From The Chunk Grid Origin\n    i32v3 _currentVoxelPos;\n};"
  },
  {
    "path": "SoA/VoxelSpaceConversions.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelSpaceConversions.h\"\n#include <Vorb/utils.h>\n\nf32v3 VoxelSpaceConversions::getCoordinateMults(const ChunkPosition2D& facePosition) {\n    f32v3 rv;\n    rv.x = (float)FACE_TO_WORLD_MULTS[facePosition.face].x;\n    rv.y = (float)FACE_Y_MULTS[facePosition.face];\n    rv.z = (float)FACE_TO_WORLD_MULTS[facePosition.face].y;\n    return rv;\n}\nf32v3 VoxelSpaceConversions::getCoordinateMults(const ChunkPosition3D& facePosition) {\n    f32v3 rv;\n    rv.x = (float)FACE_TO_WORLD_MULTS[facePosition.face].x;\n    rv.y = (float)FACE_Y_MULTS[facePosition.face];\n    rv.z = (float)FACE_TO_WORLD_MULTS[facePosition.face].y;\n    return rv;\n}\n\ni32v3 VoxelSpaceConversions::getCoordinateMapping(const ChunkPosition2D& facePosition) {\n    return VOXEL_TO_WORLD[facePosition.face];\n}\ni32v3 VoxelSpaceConversions::getCoordinateMapping(const ChunkPosition3D& facePosition) {\n    return VOXEL_TO_WORLD[facePosition.face];\n}\n\nChunkPosition2D VoxelSpaceConversions::voxelToChunk(const VoxelPosition2D& voxelPosition) {\n    ChunkPosition2D gpos;\n    gpos.face = voxelPosition.face;\n    gpos.pos.x = fastFloor(voxelPosition.pos.x / CHUNK_WIDTH);\n    gpos.pos.y = fastFloor(voxelPosition.pos.y / CHUNK_WIDTH);\n    return gpos;\n}\nChunkPosition3D VoxelSpaceConversions::voxelToChunk(const VoxelPosition3D& voxelPosition) {\n    ChunkPosition3D gpos;\n    gpos.face = voxelPosition.face;\n    gpos.pos.x = fastFloor(voxelPosition.pos.x / CHUNK_WIDTH);\n    gpos.pos.y = fastFloor(voxelPosition.pos.y / CHUNK_WIDTH);\n    gpos.pos.z = fastFloor(voxelPosition.pos.z / CHUNK_WIDTH);\n    return gpos;\n}\n\ni32v3 VoxelSpaceConversions::voxelToChunk(const i32v3& voxelPosition) {\n    i32v3 gpos;\n    gpos.x = fastFloor(voxelPosition.x / (float)CHUNK_WIDTH);\n    gpos.y = fastFloor(voxelPosition.y / (float)CHUNK_WIDTH);\n    gpos.z = fastFloor(voxelPosition.z / (float)CHUNK_WIDTH);\n    return gpos;\n}\n\ni32v3 VoxelSpaceConversions::voxelToChunk(const f64v3& voxelPosition) {\n    i32v3 gpos;\n    gpos.x = fastFloor(voxelPosition.x / CHUNK_WIDTH);\n    gpos.y = fastFloor(voxelPosition.y / CHUNK_WIDTH);\n    gpos.z = fastFloor(voxelPosition.z / CHUNK_WIDTH);\n    return gpos;\n}\n\nVoxelPosition2D VoxelSpaceConversions::chunkToVoxel(const ChunkPosition2D& gridPosition) {\n    VoxelPosition2D vpos;\n    vpos.face = gridPosition.face;\n    vpos.pos.x = gridPosition.pos.x * CHUNK_WIDTH;\n    vpos.pos.y = gridPosition.pos.y * CHUNK_WIDTH;\n    return vpos;\n}\nVoxelPosition3D VoxelSpaceConversions::chunkToVoxel(const ChunkPosition3D& gridPosition) {\n    VoxelPosition3D vpos;\n    vpos.face = gridPosition.face;\n    vpos.pos.x = gridPosition.pos.x * CHUNK_WIDTH;\n    vpos.pos.y = gridPosition.pos.y * CHUNK_WIDTH;\n    vpos.pos.z = gridPosition.pos.z * CHUNK_WIDTH;\n    return vpos;\n}\n\nf64v3 VoxelSpaceConversions::voxelToWorld(const VoxelPosition2D& facePosition, f64 voxelWorldRadius) {\n    return voxelToWorldNormalized(facePosition, voxelWorldRadius) * voxelWorldRadius;\n}\nf64v3 VoxelSpaceConversions::voxelToWorld(const VoxelPosition3D& facePosition, f64 voxelWorldRadius) {\n    return voxelToWorldNormalized(facePosition, voxelWorldRadius) * (voxelWorldRadius + facePosition.pos.y);\n}\n\nf64v3 VoxelSpaceConversions::chunkToWorld(const ChunkPosition2D& facePosition, f64 voxelWorldRadius) {\n    return chunkToWorldNormalized(facePosition, voxelWorldRadius) * voxelWorldRadius;\n}\nf64v3 VoxelSpaceConversions::chunkToWorld(const ChunkPosition3D& facePosition, f64 voxelWorldRadius) {\n    return chunkToWorldNormalized(facePosition, voxelWorldRadius) * (voxelWorldRadius + facePosition.pos.y * CHUNK_WIDTH);\n}\n\nf64v3 VoxelSpaceConversions::voxelToWorldNormalized(const VoxelPosition2D& facePosition, f64 voxelWorldRadius) {\n    const i32v3& axisMapping = VOXEL_TO_WORLD[facePosition.face];\n    const i32v2& mults = FACE_TO_WORLD_MULTS[facePosition.face];\n\n    f64v3 worldPosition;\n    worldPosition[axisMapping.x] = facePosition.pos.x * mults.x;\n    worldPosition[axisMapping.y] = voxelWorldRadius * FACE_Y_MULTS[facePosition.face];\n    worldPosition[axisMapping.z] = facePosition.pos.y * mults.y;\n\n    return glm::normalize(worldPosition);\n}\nf64v3 VoxelSpaceConversions::voxelToWorldNormalized(const VoxelPosition3D& facePosition, f64 voxelWorldRadius) {\n    const i32v3& axisMapping = VOXEL_TO_WORLD[facePosition.face];\n    const i32v2& mults = FACE_TO_WORLD_MULTS[facePosition.face];\n\n    f64v3 worldPosition;\n    worldPosition[axisMapping.x] = facePosition.pos.x * mults.x;\n    worldPosition[axisMapping.y] = voxelWorldRadius * FACE_Y_MULTS[facePosition.face];\n    worldPosition[axisMapping.z] = facePosition.pos.z * mults.y;\n\n    return glm::normalize(worldPosition);\n}\n\nf64v3 VoxelSpaceConversions::chunkToWorldNormalized(const ChunkPosition2D& facePosition, f64 voxelWorldRadius) {\n    return voxelToWorldNormalized(chunkToVoxel(facePosition), voxelWorldRadius);\n}\nf64v3 VoxelSpaceConversions::chunkToWorldNormalized(const ChunkPosition3D& facePosition, f64 voxelWorldRadius) {\n    return voxelToWorldNormalized(chunkToVoxel(facePosition), voxelWorldRadius);\n}\n\nVoxelPosition3D computeGridPosition(const f32v3& hitpoint, f32 radius) {\n    f32v3 cornerPos[2];\n    f32 min;\n    f32v3 start = glm::normalize(hitpoint) * 2.0f * radius;\n    f32v3 dir = -glm::normalize(hitpoint);\n    cornerPos[0] = f32v3(-radius, -radius, -radius);\n    cornerPos[1] = f32v3(radius, radius, radius);\n    if (!IntersectionUtils::boxIntersect(cornerPos, dir,\n        start, min)) {\n        std::cerr << \"ERROR: Failed to find grid position in computeGridPosition.\\n\";\n    }\n\n    f32v3 gridHit = start + dir * min;\n    const f32 eps = 32.0f;\n\n    VoxelPosition3D gridPos;\n\n    if (abs(gridHit.x - (-radius)) < eps) { //-X\n        gridPos.face = WorldCubeFace::FACE_LEFT;\n        gridPos.pos.x = gridHit.z;\n        gridPos.pos.z = -gridHit.y;\n    } else if (abs(gridHit.x - radius) < eps) { //X\n        gridPos.face = WorldCubeFace::FACE_RIGHT;\n        gridPos.pos.x = -gridHit.z;\n        gridPos.pos.z = -gridHit.y;\n    } else if (abs(gridHit.y - (-radius)) < eps) { //-Y\n        gridPos.face = WorldCubeFace::FACE_BOTTOM;\n        gridPos.pos.x = gridHit.x;\n        gridPos.pos.z = -gridHit.z;\n    } else if (abs(gridHit.y - radius) < eps) { //Y\n        gridPos.face = WorldCubeFace::FACE_TOP;\n        gridPos.pos.x = gridHit.x;\n        gridPos.pos.z = gridHit.z;\n    } else if (abs(gridHit.z - (-radius)) < eps) { //-Z\n        gridPos.face = WorldCubeFace::FACE_BACK;\n        gridPos.pos.x = -gridHit.x;\n        gridPos.pos.z = -gridHit.y;\n    } else if (abs(gridHit.z - radius) < eps) { //Z\n        gridPos.face = WorldCubeFace::FACE_FRONT;\n        gridPos.pos.x = gridHit.x;\n        gridPos.pos.z = -gridHit.y;\n    } else {\n        std::cerr << \"ERROR: Failed to pick voxel position in computeGridPosition.\\n\";\n    }\n\n    return gridPos;\n}\n\nVoxelPosition3D VoxelSpaceConversions::worldToVoxel(const f64v3& worldPosition, f64 voxelWorldRadius) {\n    f64v3 wpoint = glm::normalize(worldPosition) * voxelWorldRadius * 2.0;\n\n    // Compute the intersection\n    f32v3 normal, hitpoint;\n    f32 distance;\n\n    VoxelPosition3D gridPos;\n    if (IntersectionUtils::sphereIntersect(-f32v3(glm::normalize(wpoint)), f32v3(wpoint), f32v3(0.0f), (f32)voxelWorldRadius, hitpoint, distance, normal)) {\n     \n        // Compute face and grid position\n        gridPos = computeGridPosition(hitpoint, (f32)voxelWorldRadius);\n        gridPos.pos.y = glm::length(worldPosition) - voxelWorldRadius;\n    }\n\n    return gridPos;\n}"
  },
  {
    "path": "SoA/VoxelSpaceConversions.h",
    "content": "///\n/// VoxelSpaceConversions.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 27 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Converts between the different voxel coordinate spaces\n///\n\n#pragma once\n\n#ifndef VoxelSpaceConversions_h__\n#define VoxelSpaceConversions_h__\n\n#include \"Constants.h\"\n#include \"VoxelCoordinateSpaces.h\"\n#include <Vorb/utils.h>\n\n/// Namespace for converting between the different voxel and chunk coordinate spaces\nnamespace VoxelSpaceConversions {\n\n#define W_X 0\n#define W_Y 1\n#define W_Z 2\n    /// Maps face-space coordinate axis to world-space coordinates.\n    /// [face]\n    const i32v3 VOXEL_TO_WORLD[6] = {\n        i32v3(W_X, W_Y, W_Z), // TOP\n        i32v3(W_Z, W_X, W_Y), // LEFT\n        i32v3(W_Z, W_X, W_Y), // RIGHT\n        i32v3(W_X, W_Z, W_Y), // FRONT\n        i32v3(W_X, W_Z, W_Y), // BACK\n        i32v3(W_X, W_Y, W_Z) }; // BOTTOM\n#undef W_X\n#undef W_Y\n#undef W_Z\n\n    /// Multiply by the face-space Y axis in order to get the correct direction\n    /// for its corresponding world space axis\n    /// [face]\n    const int FACE_Y_MULTS[6] = { 1, -1, 1, 1, -1, -1 };\n    /// Multiply by the voxel-space X,Z axis in order to get the correct direction\n    /// for its corresponding world-space axis\n    /// [face]\n    const i32v2 FACE_TO_WORLD_MULTS[6] = {\n        i32v2(1, 1), // TOP\n        i32v2(1, -1), // LEFT\n        i32v2(-1, -1), // RIGHT\n        i32v2(1, -1), // FRONT\n        i32v2(-1, -1), // BACK\n        i32v2(1, -1) }; // BOTTOM\n\n\n    /// Gets multipliers for converting face direction to world direction\n    extern f32v3 getCoordinateMults(const ChunkPosition2D& facePosition);\n    extern f32v3 getCoordinateMults(const ChunkPosition3D& facePosition);\n    /// Gets coordinate mappings for converting face position to world position\n    extern i32v3 getCoordinateMapping(const ChunkPosition2D& facePosition);\n    extern i32v3 getCoordinateMapping(const ChunkPosition3D& facePosition);\n\n    /// Converts from voxel-space to chunk-space\n    /// Does not affect rotation or face\n    /// @param voxelPosition: The voxel grid position\n    /// @return the chunk grid position\n    extern ChunkPosition2D voxelToChunk(const VoxelPosition2D& voxelPosition);\n    extern ChunkPosition3D voxelToChunk(const VoxelPosition3D& voxelPosition);\n    extern i32v3 voxelToChunk(const i32v3& voxelPosition);\n    extern i32v3 voxelToChunk(const f64v3& voxelPosition);\n    /// Converts from chunk-space to voxel-space\n    /// Does not affect rotation or face\n    /// @param gridPosition: The chunk grid position\n    /// @return the voxel position\n    extern VoxelPosition2D chunkToVoxel(const ChunkPosition2D& gridPosition);\n    extern VoxelPosition3D chunkToVoxel(const ChunkPosition3D& gridPosition);\n   \n    /// Converts from face-space to world-space\n    /// @param facePosition: The face position\n    /// @param voxelWorldRadius: Radius of the world in units of voxels\n    /// @return the world position\n    extern f64v3 voxelToWorld(const VoxelPosition2D& facePosition, f64 voxelWorldRadius);\n    extern f64v3 voxelToWorld(const VoxelPosition3D& facePosition, f64 voxelWorldRadius);\n    /// Converts from face-space to world-space\n    /// @param facePosition: The face position\n    /// @param voxelWorldRadius: Radius of the world in units of voxels\n    /// @return the world position\n    extern f64v3 chunkToWorld(const ChunkPosition2D& facePosition, f64 voxelWorldRadius);\n    extern f64v3 chunkToWorld(const ChunkPosition3D& facePosition, f64 voxelWorldRadius);\n    /// Converts from face-space to normalized world-space\n    /// @param facePosition: The face position\n    /// @param voxelWorldRadius: Radius of the world in units of voxels\n    /// @return the normalized world position\n    extern f64v3 voxelToWorldNormalized(const VoxelPosition2D& facePosition, f64 voxelWorldRadius);\n    extern f64v3 voxelToWorldNormalized(const VoxelPosition3D& facePosition, f64 voxelWorldRadius);\n    /// Converts from face-space to normalized world-space\n    /// @param facePosition: The face position\n    /// @param voxelWorldRadius: Radius of the world in units of voxels\n    /// @return the normalized world position\n    extern f64v3 chunkToWorldNormalized(const ChunkPosition2D& facePosition, f64 voxelWorldRadius);\n    extern f64v3 chunkToWorldNormalized(const ChunkPosition3D& facePosition, f64 voxelWorldRadius);\n    /// Converts from world-space to unrotated voxel-space\n    /// @param worldSpace: World position in units of voxels. @pre should rotated so that the planet has\n    ///   a relative orientation of 0\n    /// @return the voxel position\n    extern VoxelPosition3D worldToVoxel(const f64v3& worldPosition, f64 voxelWorldRadius);\n}\n\n#endif // VoxelSpaceConversions_h__\n"
  },
  {
    "path": "SoA/VoxelSpaceUtils.cpp",
    "content": "#include \"stdafx.h\"\n#include \"VoxelSpaceUtils.h\"\n#include \"VoxelSpaceConversions.h\"\n\n\n/// Defines the effect that transitioning from face i to face j will have on\n/// rotation. Simply add to rotation value modulo 4\n/// Each rotation represents a clockwise turn.\n/// [source][destination]\n// const int FACE_TRANSITIONS[6][6] = {\n//     { 0, -1, 1, 0, 2, 0 }, // TOP\n//     { 1, 0, 0, 0, 0, -1 }, // LEFT\n//     { -1, 0, 0, 0, 0, 1 }, // RIGHT\n//     { 0, 0, 0, 0, 0, 0 }, // FRONT\n//     { 2, 0, 0, 0, 0, 2 }, // BACK\n//     { 0, 1, -1, 0, 2, 0 } }; // BOTTOM\n\n/// Neighbors, starting from +x and moving clockwise\n/// [face][rotation]\n// const WorldCubeFace FACE_NEIGHBORS[6][4] = {\n//     { FACE_RIGHT, FACE_FRONT, FACE_LEFT, FACE_BACK }, // TOP\n//     { FACE_FRONT, FACE_BOTTOM, FACE_BACK, FACE_TOP }, // LEFT\n//     { FACE_BACK, FACE_BOTTOM, FACE_FRONT, FACE_TOP }, // RIGHT\n//     { FACE_RIGHT, FACE_BOTTOM, FACE_LEFT, FACE_TOP }, // FRONT\n//     { FACE_LEFT, FACE_BOTTOM, FACE_RIGHT, FACE_TOP }, // BACK\n//     { FACE_RIGHT, FACE_BACK, FACE_LEFT, FACE_FRONT } }; // BOTTOM\n\n\n//f64q q1 = quatBetweenVectors(FACE_NORMALS[0], VoxelSpaceConversions::voxelFaceToWorldNormalized(\n//    VoxelSpaceConversions::voxelGridToFace(gridPosition), worldRadius));\n//f64q q2 = quatBetweenVectors(f32v3(1.0, 0.0, 0.0), q1 * f32v3(1.0, 0.0, 0.0))\n\n#define OFFSET 1.0\n\n/// This is basically a hack with normal mapping tangent space stuff\nf64q VoxelSpaceUtils::calculateVoxelToSpaceQuat(const VoxelPosition2D& gridPosition, f64 worldRadius) {\n\n\n    VoxelPosition2D gp2 = gridPosition;\n    gp2.pos.x += OFFSET;\n    VoxelPosition2D gp3 = gridPosition;\n    gp3.pos.y += OFFSET;\n\n    f64v3 v1 = VoxelSpaceConversions::voxelToWorldNormalized(\n        gridPosition, worldRadius);\n    f64v3 v2 = VoxelSpaceConversions::voxelToWorldNormalized(\n        gp2, worldRadius);\n    f64v3 v3 = VoxelSpaceConversions::voxelToWorldNormalized(\n        gp3, worldRadius);\n  \n    f64v3 tangent = glm::normalize(v2 - v1);\n    f64v3 biTangent = glm::normalize(v3 - v1);\n\n    f64m4 worldRotationMatrix;\n    worldRotationMatrix[0] = f64v4(tangent, 0);\n    worldRotationMatrix[1] = f64v4(v1, 0);\n    worldRotationMatrix[2] = f64v4(biTangent, 0);\n    worldRotationMatrix[3] = f64v4(0, 0, 0, 1);\n\n    return glm::quat_cast(worldRotationMatrix);\n}\nf64q VoxelSpaceUtils::calculateVoxelToSpaceQuat(const VoxelPosition3D& gridPosition, f64 worldRadius) {\n\n    VoxelPosition3D gp2 = gridPosition;\n    gp2.pos.x += OFFSET;\n\n    f64v3 v1 = VoxelSpaceConversions::voxelToWorldNormalized(\n        gridPosition, worldRadius);\n    f64v3 v2 = VoxelSpaceConversions::voxelToWorldNormalized(\n        gp2, worldRadius);\n\n    f64v3 tangent = glm::normalize(v2 - v1);\n    f64v3 biTangent = glm::cross(tangent, v1);\n   \n    f64m4 worldRotationMatrix;\n    worldRotationMatrix[0] = f64v4(tangent, 0);\n    worldRotationMatrix[1] = f64v4(v1, 0);\n    worldRotationMatrix[2] = f64v4(biTangent, 0);\n    worldRotationMatrix[3] = f64v4(0, 0, 0, 1);\n\n    return glm::quat_cast(worldRotationMatrix);\n}\n\nvoid VoxelSpaceUtils::offsetChunkGridPosition(OUT ChunkPosition2D& gridPosition, const i32v2& xzOffset, int maxPos VORB_UNUSED) {\n    gridPosition.pos += xzOffset;\n    WorldCubeFace newFace = gridPosition.face;\n\n    //TODO(Ben): New transition logic and then remove VORB_UNUSED tags.\n    //if (gridPosition.pos.y < -maxPos) { // BOTTOM SIDE\n    //    gridPosition.pos.y += maxPos;\n\n    //    newFace = FACE_NEIGHBORS[gridPosition.face][(1 + gridPosition.rotation) % 4];\n    //    gridPosition.rotation += FACE_TRANSITIONS[gridPosition.face][newFace];\n    //    if (gridPosition.rotation < 0) { gridPosition.rotation += 4; } else { gridPosition.rotation %= 4; }\n    //} else if (gridPosition.pos.y > maxPos) { // TOP SIDE\n    //    gridPosition.pos.y -= maxPos;\n\n    //    newFace = FACE_NEIGHBORS[gridPosition.face][(3 + gridPosition.rotation) % 4];\n    //    gridPosition.rotation += FACE_TRANSITIONS[gridPosition.face][newFace];\n    //    if (gridPosition.rotation < 0) { gridPosition.rotation += 4; } else { gridPosition.rotation %= 4; }\n    //}\n\n    //if (gridPosition.pos.x < -maxPos) { // LEFT SIDE\n    //    gridPosition.pos.x += maxPos;\n\n    //    newFace = FACE_NEIGHBORS[gridPosition.face][(2 + gridPosition.rotation) % 4];\n    //    gridPosition.rotation += FACE_TRANSITIONS[gridPosition.face][newFace];\n    //    if (gridPosition.rotation < 0) { gridPosition.rotation += 4; } else { gridPosition.rotation %= 4; }\n    //} else if (gridPosition.pos.x > maxPos) { // RIGHT SIDE\n    //    gridPosition.pos.x -= maxPos;\n\n    //    newFace = FACE_NEIGHBORS[gridPosition.face][gridPosition.rotation];\n    //    gridPosition.rotation += FACE_TRANSITIONS[gridPosition.face][newFace];\n    //    if (gridPosition.rotation < 0) { gridPosition.rotation += 4; } else { gridPosition.rotation %= 4; }\n    //}\n\n    gridPosition.face = newFace;\n}\n"
  },
  {
    "path": "SoA/VoxelSpaceUtils.h",
    "content": "///\n/// VoxelSpaceUtils.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 27 Jan 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Utilities for voxel coordinate space operations\n///\n\n#pragma once\n\n#ifndef VoxelSpaceUtils_h__\n#define VoxelSpaceUtils_h__\n\n#include \"VoxelCoordinateSpaces.h\"\n\nnamespace VoxelSpaceUtils {\n    /// Calculates the quaternion that can convert grid orientation to world orientation\n    /// @param gridPosition: Voxel grid position\n    /// @param worldRadius: Radius of the world in voxels\n    /// @return quaternion that describes the relative rotation\n    extern f64q calculateVoxelToSpaceQuat(const VoxelPosition2D& gridPosition, f64 worldRadius);\n    extern f64q calculateVoxelToSpaceQuat(const VoxelPosition3D& gridPosition, f64 worldRadius);\n\n    /// Offsets a chunk grid position and handles rotation\n    /// @param gridPosition: The chunk grid position\n    /// @param xzOffset: The offset to apply, in chunks\n    /// @param maxPos: Maximum grid position, for + and - direction\n    extern void offsetChunkGridPosition(ChunkPosition2D& gridPosition, const i32v2& xzOffset, int maxPos);\n\n    // TODO(Ben): implement this with new stuff\n    /* void getIterationConstants(OUT int& jStart, OUT int& jMult, OUT int& jEnd, OUT int& jInc, OUT int& kStart, OUT int& kMult, OUT int& kEnd, OUT int& kInc) {\n        switch (rotation) { //we use rotation value to un-rotate the chunk data\n            case 0: //no rotation\n                jStart = 0;\n                kStart = 0;\n                jEnd = kEnd = CHUNK_WIDTH;\n                jInc = kInc = 1;\n                jMult = CHUNK_WIDTH;\n                kMult = 1;\n                break;\n            case 1: //up is right\n                jMult = 1;\n                jStart = CHUNK_WIDTH - 1;\n                jEnd = -1;\n                jInc = -1;\n                kStart = 0;\n                kEnd = CHUNK_WIDTH;\n                kInc = 1;\n                kMult = CHUNK_WIDTH;\n                break;\n            case 2: //up is down\n                jMult = CHUNK_WIDTH;\n                jStart = CHUNK_WIDTH - 1;\n                kStart = CHUNK_WIDTH - 1;\n                jEnd = kEnd = -1;\n                jInc = kInc = -1;\n                kMult = 1;\n                break;\n            case 3: //up is left\n                jMult = 1;\n                jStart = 0;\n                jEnd = CHUNK_WIDTH;\n                jInc = 1;\n                kMult = CHUNK_WIDTH;\n                kStart = CHUNK_WIDTH - 1;\n                kEnd = -1;\n                kInc = -1;\n                break;\n        }\n    } */\n}\n\n#endif // VoxelSpaceUtils_h__"
  },
  {
    "path": "SoA/VoxelUpdateBufferer.h",
    "content": "//\n// VoxelUpdateBuffer.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 10 Sep 2015\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// Buffers voxel updates and applies all at once for minimal locking.\n//\n\n#pragma once\n\n#ifndef VoxelUpdateBuffer_h__\n#define VoxelUpdateBuffer_h__\n\n#include \"ChunkHandle.h\"\n#include \"Chunk.h\"\n\n#include <unordered_map>\n\nstruct VoxelUpdateBuffer {\n    inline void finish() { h.release(); }\n\n    ui8 bits[CHUNK_SIZE / 8]; ///< To check if an id was already added\n    std::vector<BlockIndex> toUpdate;\n    ChunkHandle h;\n};\n\n#define DIV_8_SHIFT 3\n#define MOD_8_AND 0x5\n\nclass VoxelUpdateBufferer {\npublic:\n    void reserve(std::unordered_map<ChunkID, VoxelUpdateBuffer>::size_type sizeApprox) {\n        buffers.reserve(sizeApprox);\n    }\n    inline void addUpdate(ChunkHandle chunk, BlockIndex index) {\n        auto it = buffers.find(chunk->getID());\n        if (it == buffers.end()) {\n            // TODO(Ben): Verify that there is no extra copy.\n            VoxelUpdateBuffer nbuff = {};\n            VoxelUpdateBuffer& b = buffers.emplace(chunk->getID(), std::move(nbuff)).first->second;\n            // Set the bit\n            b.bits[index >> DIV_8_SHIFT] |= (1 << (index & MOD_8_AND));\n            b.toUpdate.push_back(index);\n            b.h = chunk.acquire();\n        } else {\n            VoxelUpdateBuffer& b = it->second;\n            ui8& byte = b.bits[index >> DIV_8_SHIFT];\n            BlockIndex bitMask = (1 << (index & MOD_8_AND));\n            // Don't set it twice\n            if (!(byte & bitMask)) {\n                byte |= bitMask;\n                b.toUpdate.push_back(index);\n            }\n        }\n    }\n\n    // You must manually call finish on all buffers then clear it yourself\n    std::unordered_map<ChunkID, VoxelUpdateBuffer> buffers;\n};\n\n#endif // VoxelUpdateBuffer_h__\n"
  },
  {
    "path": "SoA/VoxelUpdateOrder.inl",
    "content": "#pragma once\n\n#include \"Constants.h\"\n\n// Randomly generated permutation of 32768 for fast \"random\" block updates\nconst int RandomUpdateOrder[CHUNK_SIZE] = { 41, 18467, 6334, 26500, 19169, 15724, 11478, 29358, 26962, 24464, 5705, 28145, 23281,\n16827, 9961, 491, 2995, 11942, 4827, 5436, 32391, 14604, 3902, 153, 292, 12382, 17421, 18716, 19718, 19895, 5447, 21726,\n14771, 11538, 1869, 19912, 25667, 26299, 17035, 9894, 28703, 23811, 31322, 30333, 17673, 4664, 15141, 7711, 28253, 6868,\n25547, 27644, 32662, 42, 20037, 12859, 8723, 9741, 27529, 778, 12316, 3035, 22190, 1842, 288, 30106, 9040, 8942, 19264,\n22648, 27446, 23805, 15890, 6729, 24370, 15350, 15006, 31101, 24393, 3548, 19629, 12623, 24084, 19954, 18756, 11840, 4966,\n7376, 13931, 26308, 16944, 32439, 24626, 11323, 5537, 21538, 16118, 2082, 22929, 16541, 4833, 31115, 4639, 29658, 22704,\n9930, 13977, 2306, 31673, 22386, 5021, 28745, 26924, 19072, 6270, 5829, 26777, 15573, 5097, 16512, 23986, 13290, 9161, 18636,\n22355, 24767, 23655, 15574, 4031, 12052, 27350, 1150, 16941, 21724, 13966, 3430, 31107, 30191, 18007, 11337, 15457, 12287,\n27753, 10383, 14945, 8909, 32209, 9758, 24221, 18588, 6422, 24946, 27506, 13030, 16413, 29168, 900, 32591, 18762, 1655, 17410,\n6359, 27624, 20537, 21548, 6483, 27595, 4041, 3602, 24350, 10291, 30836, 9374, 11020, 4596, 24021, 27348, 23199, 19668, 24484,\n8281, 4734, 53, 1999, 26418, 27938, 6900, 3788, 18127, 467, 3728, 14893, 24648, 22483, 17807, 2421, 14310, 6617, 22813, 9514,\n14309, 7616, 18935, 17451, 20600, 5249, 16519, 31556, 22798, 30303, 6224, 11008, 5844, 54, 14989, 149, 3195, 20485, 3093, 14343,\n30523, 1587, 29314, 9503, 7448, 25200, 13458, 6618, 20580, 19796, 14798, 15281, 19589, 20798, 28009, 27157, 20472, 23622, 18538, 12292, 6038, 24179, 18190, 29657, 7958, 6191, 19815, 22888, 19156, 11511, 16202, 2634, 24272, 20055, 20328, 22646, 26362, 4886,\n18875, 28433, 29869, 20142, 23844, 1416, 21881, 31998, 10322, 18651, 10021, 5699, 3557, 28476, 27892, 24389, 5075, 10712, 2600, 2510, 21003, 26869, 17861, 14688, 13401, 9789, 15255, 16423, 5002, 10585, 24182, 10285, 27088, 31426, 28617, 23757, 9832, 30932,\n4169, 2154, 25721, 17189, 19976, 31329, 2368, 28692, 21425, 10555, 3434, 16549, 7441, 9512, 30145, 18060, 21718, 3753, 16139, 12423, 16279, 25996, 16687, 12529, 22549, 17437, 19866, 12949, 193, 23195, 3297, 20416, 28286, 16105, 24488, 16282, 12455, 25734,\n18114, 11701, 31316, 20671, 5786, 12263, 4313, 24355, 31185, 20053, 912, 10808, 1832, 20945, 32427, 27756, 28321, 19558, 23646, 27982, 481, 4144, 23196, 20222, 7129, 2161, 5535, 20450, 11173, 10466, 12044, 21659, 26292, 26439, 17253, 20024, 26154, 29510,\n4745, 20649, 13186, 8313, 4474, 28022, 2168, 14018, 18787, 9905, 17958, 7391, 10202, 3625, 26477, 4414, 9314, 25824, 29334, 25874, 24372, 20159, 11833, 28070, 7487, 28297, 7518, 8177, 17773, 32270, 1763, 2668, 17192, 13985, 3102, 8480, 29213, 7627, 4802,\n4099, 30527, 2625, 1543, 1924, 11023, 29972, 13061, 14181, 31003, 27432, 17505, 27593, 22725, 13031, 8492, 142, 17222, 31286, 13064, 7900, 19187, 8360, 22413, 30974, 14270, 29170, 235, 30833, 19711, 25760, 18896, 4667, 7285, 12550, 140, 13694, 2695, 21624\n, 28019, 2125, 26576, 21694, 22658, 26302, 17371, 22466, 4678, 22593, 23851, 25484, 1018, 28464, 21119, 23152, 2800, 18087, 31060, 1926, 9010, 4757, 32170, 20315, 9576, 30227, 12043, 22758, 7164, 5109, 7882, 17086, 29565, 3487, 29577, 14474, 32354, 25627,\n5629, 31928, 25423, 28520, 6902, 14962, 123, 24596, 3737, 13261, 10195, 256, 1264, 8260, 6202, 8116, 5030, 20326, 29011, 30771, 6411, 32717, 21153, 21520, 29790, 14924, 30188, 21763, 4940, 20851, 18662, 13829, 30900, 17713, 18958, 17578, 8365, 13007, 11477,\n1200, 26058, 6439, 2303, 12760, 19357, 2324, 6477, 5108, 21113, 14887, 19801, 22850, 14460, 22428, 12993, 27384, 19405, 6540, 31111, 28704, 12835, 137, 6072, 29350, 18823, 14485, 20556, 23216, 1626, 9357, 8526, 13357, 29337, 23271, 23869, 29361, 12896, 13022,\n29617, 10112, 12717, 18696, 11585, 24041, 24423, 24129, 24229, 4565, 6559, 8932, 22296, 29855, 12053, 16962, 3584, 29734, 6654, 16972, 21457, 14369, 22532, 2963, 2607, 2483, 911, 11635, 10067, 22848, 4675, 12938, 2223, 22142, 23754, 6511, 22741, 20175, 21459,\n17825, 3221, 17870, 32211, 31934, 15205, 31783, 23850, 17398, 22279, 22701, 12193, 12734, 1637, 26534, 5556, 1993, 10176, 25705, 6962, 10548, 15881, 300, 14413, 16641, 19855, 24855, 13142, 11462, 27611, 30877, 20424, 547, 1752, 18443, 28296, 12673, 10040,\n9313, 875, 20072, 12818, 610, 1017, 14932, 28112, 30695, 13169, 23831, 20040, 26488, 28685, 19090, 19497, 2589, 25990, 15145, 19353, 19314, 32500, 26740, 22044, 11258, 335, 8759, 11192, 7605, 25264, 12181, 28503, 3829, 23775, 20608, 29292, 5997, 17549,\n29556, 25561, 31627, 6467, 29541, 26129, 31240, 27813, 29174, 20601, 6077, 20215, 8683, 8213, 23992, 32378, 5601, 23392, 15759, 2670, 26428, 28027, 4084, 10075, 18786, 15498, 24970, 6287, 23847, 546, 503, 21221, 22663, 5706, 2363, 32297, 22171, 27489,\n18240, 12164, 25542, 7619, 20913, 7591, 6704, 31818, 9232, 750, 25205, 4975, 1539, 303, 11422, 21098, 11247, 13584, 13648, 2971, 17864, 22913, 11075, 21545, 28712, 17546, 18678, 1769, 15262, 8519, 32362, 28289, 15944, 2865, 18540, 23245, 25508, 28318,\n27870, 9601, 28323, 21132, 24472, 27152, 25087, 28570, 29763, 29901, 17103, 14423, 3527, 11600, 26969, 14015, 5565, 28, 21543, 25347, 2088, 2943, 12637, 22409, 26463, 5049, 4681, 1588, 11342, 608, 79, 32055, 1758, 29954, 20888, 14146, 690, 7949, 12843,\n21430, 25620, 748, 27067, 4536, 20783, 18035, 261, 15185, 7038, 9853, 25629, 11224, 15748, 19923, 3359, 301, 24766, 4944, 14955, 23318, 775, 25411, 21025, 20355, 31001, 32447, 9496, 18584, 9515, 17964, 23342, 8075, 17913, 16142, 31196, 21948, 25072, 20426,\n14606, 26173, 24429, 474, 6705, 20626, 29812, 19375, 30093, 16565, 16036, 14736, 29141, 30814, 5994, 8256, 6652, 23936, 30838, 20482, 1355, 21015, 1131, 18230, 17841, 14625, 2011, 731, 4186, 19690, 1650, 5662, 21634, 10893, 10353, 21416, 13452, 14008, 7262,\n22233, 5454, 16303, 16634, 26303, 14256, 148, 11124, 12317, 4213, 27109, 24028, 29200, 21080, 21318, 16858, 24050, 24155, 31361, 15264, 11903, 3676, 29643, 26909, 14902, 3561, 28489, 24948, 1282, 13653, 30674, 2220, 5402, 6923, 3831, 19369, 3878, 20259,\n19008, 22619, 23971, 30003, 21945, 9781, 26504, 12392, 837, 25313, 6698, 5589, 12722, 5938, 19037, 6410, 31461, 6234, 12508, 32753, 3959, 6493, 1515, 25269, 24937, 28869, 58, 14700, 13971, 26264, 15117, 16215, 24555, 7815, 18330, 3039, 30212, 29288, 28082,\n1954, 16085, 20710, 32588, 24774, 8380, 29815, 25951, 6541, 18115, 1679, 17110, 25898, 23073, 788, 23977, 18132, 29956, 28689, 26113, 10008, 12941, 15790, 1723, 21363, 31993, 25184, 24778, 7200, 5071, 1885, 21974, 1071, 11333, 22867, 26153, 14295, 388,\n20825, 9676, 15629, 28650, 2598, 3309, 4693, 4686, 30080, 10116, 12249, 26667, 1528, 26679, 7864, 29421, 8405, 8826, 6816, 7516, 27726, 28666, 29087, 27681, 19964, 1340, 5686, 6021, 11662, 14721, 6064, 29309, 20415, 17902, 29873, 17124, 23941, 1003, 21,\n28423, 27531, 4806, 12268, 9318, 5602, 173, 24307, 23481, 1012, 21136, 26630, 24114, 26809, 32064, 23556, 12290, 21293, 29996, 29152, 1054, 25345, 14708, 248, 7491, 13712, 5131, 30114, 16439, 32523, 24722, 29704, 6995, 1052, 31832, 7479, 18238, 26423,\n27918, 10866, 17659, 799, 28486, 21196, 7462, 26633, 12158, 12022, 1146, 18392, 13037, 3925, 10647, 29458, 6602, 30807, 4098, 27830, 32089, 14600, 7278, 20799, 18352, 20448, 13882, 540, 28315, 4575, 8762, 9567, 22336, 18397, 31418, 19897, 25828, 13851,\n26816, 24230, 4449, 16925, 658, 229, 24520, 10940, 29560, 15147, 25162, 32608, 20675, 792, 22361, 105, 16398, 23146, 8714, 26946, 21188, 19569, 8638, 27663, 15075, 24515, 11521, 475, 15615, 20528, 13234, 12570, 905, 9464, 19557, 28962, 14161, 30524, 12549,\n17469, 330, 32140, 28350, 14333, 22925, 10910, 19737, 16336, 18337, 1278, 12393, 7636, 30714, 28164, 31591, 19949, 19135, 2505, 13337, 10004, 16337, 2623, 28664, 9970, 25608, 30568, 19281, 7085, 9152, 18373, 28652, 8194, 9876, 23826, 28396, 7572, 6249,\n14640, 32078, 18819, 943, 1028, 1941, 20289, 8419, 31994, 3805, 7585, 16216, 31450, 1615, 2609, 11064, 9166, 16893, 16074, 13509, 30300, 19695, 9573, 15589, 13161, 31172, 17968, 27358, 26031, 26268, 19426, 28510, 10422, 30774, 8779, 30910, 23552, 4182,\n25391, 15495, 5764, 874, 1364, 31869, 28255, 4460, 31929, 6972, 26821, 26122, 32258, 21577, 32484, 25605, 30195, 27594, 7950, 16343, 754, 2481, 31730, 11672, 23439, 13428, 5912, 9762, 5967, 24408, 4415, 1908, 17223, 11759, 26434, 5204, 29486, 4319, 958,\n5945, 26806, 8166, 18700, 11367, 17692, 21787, 28532, 30556, 32332, 3447, 32657, 18283, 26222, 29331, 2376, 28583, 26948, 12723, 17982, 22018, 14776, 9220, 32221, 696, 23856, 19490, 8925, 4324, 6486, 19677, 15969, 11643, 7534, 15677, 22668, 31068, 21991,\n724, 7783, 16828, 7727, 29426, 15871, 10697, 17612, 18703, 11027, 11408, 5545, 9508, 7185, 30238, 24237, 26443, 21313, 22501, 8850, 25128, 2111, 23650, 28149, 32097, 1454, 15869, 681, 27465, 20267, 32246, 19793, 18634, 25472, 20972, 22830, 24901, 28442, 5177, 13877, 25770, 702, 14364, 1381, 16590, 8823, 2237, 8023, 755, 16595, 20169, 2327, 12042, 31310, 28182, 11058, 7926, 9487, 1670, 1115, 5651, 2258, 7213, 9860, 25783, 21286, 2742, 8610, 4472, 7128, 18434, 5841, 20718, 3503, 14867, 24865, 10938, 1881, 9257, 22750, 28614, 18598, 28458, 2661, 26063, 1369, 20807, 20278, 19489, 19435, 6365, 694, 7586, 1386, 7833, 32334, 13330, 26048, 8928, 29492, 12433, 23840, 6766, 1735, 19810, 11599, 11837, 21892, 618, 7328, 29352, 11369, 31244, 21794, 6608, 9252, 11647, 17432, 9535, 7208, 3264, 3497, 23243, 27649, 22015, 26841, 189, 16100, 19812, 30648, 9523, 19851, 24474, 28633, 29891, 27200, 19854, 9990, 25697, 4919, 17780, 22578, 12931, 1215, 3340, 13487, 899, 22525, 8483, 5538, 7492, 6193, 28252, 25011, 1560, 15834, 1840, 182, 2785, 18529, 228, 18805, 28791, 13392, 13210, 13549, 21578, 26979, 30971, 9277, 73, 20193, 1620, 21497, 13826, 31276, 19790, 6582, 13578, 11159, 20418, 26489, 159, 3449, 12924, 9072, 10380, 27008, 27967, 10208, 32233, 18503, 15370, 1328, 14196, 12074, 13722, 12611, 19019, 28761, 11056, 12890, 31163, 16683, 13716, 19932, 25452, 2741, 4954, 6813, 2862, 10396, 15460, 20615, 10904, 2599, 20136, 4680, 9198, 27032, 14387, 1333, 7240, 3517, 17006, 8670, 241, 18882, 25249, 3523, 516, 12105, 29621, 17095, 7296, 9916, 15678, 10178, 13579, 25058, 27577, 12750, 14007, 23729, 24081, 32751, 2678, 24676, 32625, 20899, 11784, 15565, 32549, 13608, 6172, 11243, 29929, 7514, 10168, 5055, 11191, 5973, 8922, 6748, 31411, 10986, 2144, 16446, 373, 26517, 14629, 29916, 5874, 15791, 15469, 22912, 8146, 30693, 9091, 9815, 26949, 26857, 20640, 26052, 236, 8551, 31414, 32767, 28162, 16955, 23183, 8394, 30180, 16097, 3065, 27065, 2513, 9261, 12578, 21078, 16878, 14140, 4611, 32708, 2445, 170, 29975, 13489, 24750, 6149, 3333, 13865, 22214, 17282, 27007, 32346, 8896, 16367, 28522, 4882, 31659, 17641, 7231, 2187, 32278, 6479, 6321, 6538, 207, 19447, 24208, 9646, 22276, 25759, 30189, 30422, 27666, 8486, 3455, 2028, 29614, 4860, 29253, 11777, 220, 12503, 10861, 22431, 29082, 32435, 14197, 22106, 8752, 15821, 17296, 26281, 26021, 24455, 15947, 27124, 18318, 9135, 11376, 1774, 29859, 24998, 31296, 9253, 6922, 10635, 1643, 28888, 8153, 13232, 4747, 28680, 19926, 25678, 6450, 14801, 24961, 14199, 20855, 26363, 5716, 10573, 31636, 32013, 6473, 28274, 1550, 24353, 1181, 4287, 2699, 18110, 18643, 17465, 7172, 2529, 9981, 2112, 13476, 4381, 8247, 26890, 16671, 8805, 1308, 30032, 3989, 9320, 23165, 15431, 9658, 11293, 17206, 26578, 16948, 2206, 27171, 18166, 3396, 16697, 31020, 23694, 15529, 14788, 30109, 17984, 11969, 28978, 21617, 4015, 16626, 3684, 9168, 17906, 25928, 12097, 28118, 24390, 15199, 11785, 14486, 19199, 12420, 31814, 18271, 15813, 27415, 6085, 318, 3580, 1331, 7267, 8387, 13444, 23186, 14507, 4360, 17827, 28074, 26431, 7152, 30271, 10268, 31772, 19885, 337, 309, 17604, 12677, 406, 7768, 29022, 19413, 5000, 542, 17537, 30038, 21388, 7355, 13289, 659, 3181, 13093, 16584, 10987, 10761, 20493, 8217, 9501, 17482, 29447, 15665, 10753, 22104, 15084, 19095, 13525, 30221, 3964, 21781, 4872, 8106, 3656, 3343, 32308, 27080, 16080, 14868, 21411, 13713, 20968, 3251, 27216, 12079, 28768, 17040, 579, 12933, 23779, 20663, 12259, 26653, 27936, 2095, 24365, 11874, 7720, 26835, 25680, 8976, 18455, 5725, 4071, 24808, 13559, 9156, 31734, 17832, 7905, 10440, 7375, 21562, 22885, 21962, 31880, 1836, 10797, 281, 10508, 10080, 5340, 12076, 9058, 578, 7740, 8546, 20474, 24773, 19097, 8880, 23335, 11072, 23400, 707, 22955, 20666, 4141, 23588, 12481, 17168, 32659, 19396, 16225, 1009, 22012, 18136, 11455, 32609, 25043, 742, 31740, 17922, 24512, 9248, 26018, 27368, 23717, 9714, 17650, 32646, 3335, 12759, 3169, 21895, 5303, 22640, 21979, 24199, 29105, 24791, 18661, 8681, 3652, 8753, 24033, 1166, 15987, 7042, 26253, 20083, 11420, 15814, 1862, 12244, 209, 7229, 20652, 18864, 4769, 30470, 15005, 21047, 1594, 21487, 24326, 3276, 21323, 32222, 7679, 23990, 1750, 24710, 29271, 17945, 29221, 28470, 20183, 23589, 23955, 4978, 24779, 5006, 13262, 20135, 23487, 27196, 29033, 31990, 12935, 19779, 15993, 14790, 24962, 18965, 11001, 19105, 11807, 24567, 2669, 3134, 1863, 1457, 12998, 3545, 13597, 14218, 8838, 14844, 7372, 8563, 21028, 29264, 28801, 14723, 13490, 7604, 809, 24227, 11197, 23692, 19771, 20363, 29301, 22363, 7721, 3565, 32741, 23445, 18610, 495, 16741, 15022, 1036, 29151, 23015, 8055, 3393, 8738, 15279, 19882, 1608, 12654, 3822, 1942, 24245, 1338, 144, 22290, 30951, 23154, 24604, 4623, 22225, 20078, 32634, 1228, 2330, 29733, 28223, 20594, 29130, 18846, 4987, 29445, 31667, 8616, 5750, 20489, 27338, 21963, 28135, 14697, 1473, 21630, 23224, 31517, 26737, 31339, 1190, 27372, 10293, 3855, 6734, 9561, 332, 27606, 8184, 7075, 28382, 14119, 6741, 30432, 24684, 12779, 12279, 31497, 20667, 125, 24125, 24118, 12737, 18028, 1413, 20577, 10737, 14091, 32213, 22795, 16060, 21901, 8793, 3432, 2136, 4580, 14875, 5907, 21184, 31009, 8719, 26790, 20476, 30041, 3351, 8329, 16290, 22974, 23072, 3591, 12189, 15787, 812, 3239, 32576, 3053, 17063, 10681, 25903, 27005, 24176, 18479, 1695, 6139, 1802, 13998, 21083, 23639, 29515, 27621, 29993, 15826, 15722, 23838, 24828, 12581, 24399, 8978, 11891, 1023, 26943, 24834, 14243, 7349, 2702, 8707, 20502, 25141, 10687, 8346, 15891, 24637, 18413, 11400, 22816, 1055, 13162, 8935, 29126, 19410, 19877, 11382, 26260, 27189, 26705, 13874, 2663, 20722, 1573, 22566, 16360, 32527, 32618, 7811, 28245, 9467, 1811, 26867, 13189, 10542, 13063, 21547, 30502, 32201, 9099, 25023, 17226, 600, 30048, 21051, 1570, 8636, 9458, 25967, 8456, 9405, 11531, 29962, 26819, 7975, 10556, 7531, 907, 8044, 5, 26803, 3388, 18915, 7450, 12319, 6272, 25791, 29383, 10133, 1775, 24642, 23569, 18300, 17954, 12078, 3585, 2257, 25333, 893, 10490, 10103, 4750, 17233, 10722, 24271, 19611, 18990, 30338, 21641, 23258, 19047, 2352, 31057, 479, 25302, 2133, 30558, 10002, 15568, 4422, 16895, 6135, 18008, 12361, 16742, 22194, 23699, 23188, 20178, 4042, 822, 31742, 1847,\n7469, 16345, 4380, 1384, 14964, 25710, 20061, 25385, 20073, 27504, 9462, 2182, 28102, 11069, 5154, 3529, 30775, 1559, 19149, 3730, 2244, 10844, 13049, 14118, 24065, 31088, 19552, 28773, 18470, 29731, 6747, 7511, 5869, 14398, 10498, 7103, 27352, 25679, 28053, 13043, 14522, 597, 1563, 25834, 9850, 17022, 31249, 21911, 9492, 31207, 28580, 15477, 27616, 29876, 19178, 5220, 14615, 22348, 26798, 1706, 1163, 16857, 2883, 1662, 18902, 28262, 19420, 19770, 19022, 9273, 25841, 12686, 31100, 3917, 1259, 1892, 13698, 11267, 11749, 65, 10389, 6932, 25619, 16081, 2003, 30747, 13028, 18631, 14589, 32302, 18630, 19172, 19864, 6407, 12295, 25428, 29681, 18490, 26610, 26177, 639, 25236, 6459, 20643, 16840, 27633, 27037, 23893, 22630, 20274, 32225, 28782, 1783, 17461, 8290, 19662, 22307, 20997, 737, 18423, 8890, 16717, 6640, 32727, 5566, 4883, 23661, 22659, 18245, 20386, 2249, 2364, 19601, 30427, 17209, 1497, 27283, 29250, 18058, 8421, 175, 190, 26787, 3271, 31078, 27999, 12504, 24979, 2138, 10700, 530, 2461, 12118, 205, 7540, 18828, 24459, 11622, 30498, 3760, 27098, 30819, 10481, 245, 19567, 18493, 28596, 19161, 7746, 10538, 7670, 20538, 21476, 21555, 24917, 16371, 16760, 5752, 13758, 15433, 1903, 29065, 726, 2401, 3034, 30876, 10393, 203, 27273, 18792, 16193, 30950, 30137, 32000, 3690, 28211, 32320, 24668, 2293, 7498, 989, 15248, 3879, 31355, 11149, 604, 669, 550, 25598, 25449, 25436, 24599, 20123, 1443, 1731, 18154, 22861, 4434, 9385, 23967, 10816, 11393, 16704, 29866, 645, 1, 30749, 18684, 488, 22667, 10048, 32389, 13930, 512, 19814, 16090, 5427, 23743, 1604, 10599, 16474, 7195, 506, 5158, 17589, 9858, 27809, 17889, 11447, 40, 3818, 9364, 17975, 26, 25089, 2503, 30066, 26412, 6840, 31632, 14676, 25395, 28641, 29986, 17651, 21109, 8187, 30858, 21085, 23390, 988, 18686, 4755, 11381, 28128, 25502, 24277, 607, 26424, 30782, 3872, 832, 635, 14428, 6646, 20889, 6478, 10883, 24925, 21265, 32305, 5045, 20778, 5821, 13855, 2520, 12927, 31551, 25134, 27251, 22675, 13336, 16334, 21001, 2737, 9310, 5974, 7590, 20356, 31784, 1858, 10935, 1925, 31158, 1825, 18718, 13573, 4712, 31689, 4998, 32386, 7162, 1717, 8692, 19539, 28047, 10946, 19103, 27, 24115, 839, 25858, 20829, 2645, 3394, 17199, 19645, 14272, 675, 21862, 1880, 13773, 2480, 11238, 26897, 3542, 29608, 19203, 23277, 6125, 20134, 1401, 9078, 18382, 31421, 20736, 27478, 17939, 21138, 18721, 1254, 10663, 1677, 21575, 6724, 25981, 27700, 7961, 28862, 16002, 18448, 25095, 684, 24016, 15137, 9507, 13993, 21284, 2944, 106, 821, 7058, 24643, 17668, 10677, 119, 29857, 23041, 8891, 32095, 1623, 6915, 8072, 17929, 841, 4715, 17615, 12536, 14957, 27759, 700, 31896, 5093, 24241, 11829, 12448, 5227, 11798, 16224, 10324, 12274, 18133, 30925, 15038, 12170, 6862, 31175, 5084, 11909, 14878, 31860, 27085, 29400, 23024, 14193, 23105, 9412, 15765, 5767, 15407, 30147, 13784, 704, 30816, 9834, 10891, 621, 18085, 27734, 25190, 20542, 17998, 22086, 1929, 15621, 31002, 22597, 21376, 24254, 29669, 18108, 30235, 12493, 26068, 6366, 9102, 2438, 12600, 10819, 14318, 2290, 14984, 16339, 2556, 25808, 4632, 21478, 26814, 13787, 7239, 30690, 25020, 10827, 2554, 1988, 32459, 16798, 13642, 19002, 16321, 52, 13946, 7056, 18509, 29833, 17708, 19761, 6533, 20686, 14804, 26385, 10142, 18842, 17260, 22161, 1583, 4343, 9578, 1187, 113, 30609, 4591, 5934, 31746, 656, 29761, 25012, 28411, 11959, 16251, 18738, 13370, 26124, 5507, 8007, 17584, 10951, 23101, 14489, 24958, 15441, 1790, 17013, 403, 14855, 21060, 7093, 8472, 25402, 2673, 13543, 7373, 6266, 27651, 15275, 21528, 532, 30982, 5469, 32490, 32292, 17107, 32495, 2451, 17953, 28392, 22570, 13519, 19472, 23407, 22494, 9505, 28440, 20383, 14262, 21409, 28607, 18038, 31011, 5471, 11171, 20654, 29947, 11514, 14523, 21229, 489, 31369, 17887, 29756, 26632, 7470, 25739, 30902, 8522, 7283, 8160, 17553, 24705, 27091, 30457, 25386, 1737, 4629, 32714, 28317, 22045, 12356, 13388, 31265, 3154, 525, 32373, 27760, 26919, 25631, 6738, 21267, 25776, 32033, 24314, 16320, 13053, 24007, 16469, 24216, 9722, 19842, 29007, 15463, 30627, 1026, 13793, 28630, 18717, 23043, 1460, 25314, 31037, 17117, 1334, 20620, 14171, 26792, 8964, 19154, 18866, 14693, 760, 32091, 13000, 12212, 21100, 7551, 25476, 6379, 10943, 17877, 3789, 361, 11385, 8272, 11434, 15144, 29561, 25563, 14504, 12946, 23888, 20308, 12157, 1430, 5123, 6464, 4074, 4346, 13837, 1981, 25318, 26611, 16292, 17591, 3832, 27123, 6461, 16991, 1595, 27330, 28498, 17369, 17291, 8400, 14179, 24117, 2317, 19914, 29865, 1441, 5936, 21867, 7028, 1602, 27909, 13973, 17981, 11503, 26569, 31760, 1883, 25367, 5385, 28402, 5230, 17157, 28681, 15567, 8310, 1866, 3687, 13171, 3477, 1414, 2934, 6238, 27671, 2047, 26115, 4592, 27311, 2834, 1405, 32585, 7171, 32539, 22740, 22530, 13675, 24320, 25790, 13377, 10998, 16586, 21604, 4489, 19631, 29744, 8388, 30433, 30216, 29937, 18259, 5927, 14609, 28119, 21479, 22716, 6300, 21396, 16853, 11458, 20830, 24593, 1016, 60, 14854, 32515, 26160, 12294, 12054, 26333, 146, 4229, 10471, 10428, 10559, 22241, 31763, 22688, 16366, 12033, 26685, 2270, 25329, 2492, 22860, 2208, 8982, 22162, 31405, 6878, 11979, 1897, 7887, 31144, 14469, 29920, 17540, 30700, 7266, 18633, 31567, 24557, 32457, 26134, 2305, 18135, 12258, 2593, 17843, 21693, 16466, 22951, 18140, 11094, 12937, 5174, 2512, 6097, 9551, 32319, 21817, 23492, 21292, 20237, 27530, 613, 25296, 21710, 2665, 5628, 5809, 28786, 2024, 18840, 8182, 28569, 6120, 27393, 6292, 32274, 14214, 12527, 26807, 13194, 8705, 14713, 7011, 18913, 6693, 19664, 26203, 28995, 17762, 14381, 31644, 212, 1048, 21768, 26624, 22511, 7954, 4235, 1127, 14633, 28240, 30855, 15127, 31231, 23817, 2340, 30040, 15100, 28400, 6558, 30359, 29941, 30220, 16430, 5831, 21295, 3537, 15623, 30886, 2927, 28029, 544, 16211, 11754, 26880, 12253, 3293, 21321, 20785, 26528, 10443, 1343, 32462, 24671, 9270, 7452, 9375, 14631, 13640, 8934, 18040, 7986, 28834, 14248, 32036, 28765, 12796, 10312, 31894, 25052, 1093, 23987, 32758, 2922, 29644, 32086, 20170, 5450, 27182, 7301, 13293, 24099, 23332, 19044, 2707, 75, 1382, 19050, 15026, 14066, 11738, 32229, 19623, 13843, 441, 3380, 31565, 7918, 3659, 1363, 12628, 6329, 1088, 28854, 8613, 30384, 18569, 666, 30839, 29684, 27837, 3402, 23115, 23292, 31793, 2872, 29448, 732, 11153, 15948, 24395, 25197, 4508, 22908, 17411, 30155, 7665, 26781, 3202, 17610, 30655, 27256, 27705, 8965, 18023, 20769, 11715, 20253, 2235, 23684, 29478, 2578, 21840, 833, 19285, 26900, 10968, 23994, 16633, 13885, 348, 18281, 18032, 16256, 356, 10872, 29765, 23901, 12306, 31102, 17860, 2924, 29527, 7137, 8343, 9768, 28233, 3995, 29171, 7603, 28942, 18011, 7879, 1499, 14512, 32255, 30381, 32084, 23234, 10258, 21926, 5906, 5191, 14443, 6188, 30099, 3197, 26484, 5224, 19093, 917, 13224, 28094, 3582, 8867, 8627, 22005, 11146, 3176, 16589, 20540, 18237, 32228, 18759, 30034, 28956, 3175, 2403, 28042, 29795, 15811, 5225, 21143, 21595, 21016, 26615, 28804, 21006, 28368, 2152, 847, 698, 1325, 28313, 28023, 22312, 24618, 18457, 18396, 8339, 21086, 2617, 7846, 27043, 2048, 12911, 16280, 23455, 26358, 26847, 28870, 990, 3873, 4327, 3413, 3454, 2434, 12472, 24450, 17241, 4641, 5646, 23525, 28213, 16824, 30138, 8695, 25403, 12594, 7993, 26067, 22187, 4640, 25079, 10041, 18125, 12534, 31130, 23000, 4907, 3183, 27692, 25293, 5117, 7717, 20403, 3943, 17893, 10639, 32261, 26925, 31882, 19978, 10748, 2850, 22892, 26444, 10654, 23623, 31080, 12036, 2130, 21346, 826, 16061, 3904, 10238, 17571, 26886, 16405, 5299, 22056, 11728,\n1267, 3751, 2019, 19991, 31050, 5717, 25846, 17093, 3187, 1421, 31936, 6867, 28299, 3052, 30289, 1201, 3328, 24942, 7104, 1768, 383, 26641, 16296, 11262, 10720, 21244, 31701, 9625, 21219, 30016, 18174, 10984, 10459, 13149, 17014, 5695, 31126, 5032, 31664, 1537, 30064, 8363, 4651, 1219, 24290, 25917, 21683, 2560, 26584, 27252, 3586, 1915, 26248, 12137, 2397, 424, 23168, 20027, 28148, 2647, 10382, 30835, 27669, 30566, 20877, 1014, 19104, 484, 31989, 11495, 26811, 1293, 28892, 6798, 1990, 11299, 14890, 8493, 29074, 1549, 13774, 32379, 20173, 24069, 29218, 26865, 16833, 15238, 19911, 13252, 6463, 6508, 25149, 23088, 12245, 6231, 2611, 10106, 19271, 12368, 6421, 15258, 4157, 9647, 4982, 31703, 24122, 17723, 906, 18706, 10189, 11156, 31706, 12351, 30111, 7118, 2261, 2097, 11836, 10591, 13406, 4510, 25813, 14651, 25880, 27844, 24743, 7741, 11245, 14578, 4949, 21705, 24514, 19785, 9227, 8624, 17204, 28356, 23917, 6227, 555, 10102, 14286, 19468, 11698, 8979, 30959, 12489, 10758, 30793, 1520, 28410, 17132, 27089, 27296, 11950, 23112, 20122, 32448, 7672, 25836, 18277, 5553, 13976, 10670, 9085, 29463, 1751, 1160, 19751, 29001, 435, 16693, 15072, 17916, 6716, 25328, 1511, 2898, 11838, 30394, 18939, 11544, 1056, 12826, 12902, 26758, 24588, 12021, 22586, 14108, 563, 29607, 30871, 26947, 31625, 1280, 13245, 31451, 14062, 10426, 4719, 30101, 29091, 4047, 13785, 23231, 7406, 8684, 21954, 16769, 14709, 27956, 22421, 15945, 13465, 16016, 21860, 16497, 18335, 5190, 5677, 28049, 21005, 7886, 23388, 18675, 13143, 17377, 10130, 28487, 26555, 22482, 25253, 15000, 27754, 289, 3320, 25215, 12008, 2145, 940, 27799, 2997, 9707, 8454, 304, 8237, 10485, 12499, 32149, 459, 3459, 18682, 12983, 15351, 16129, 17137, 5033, 16600, 2719, 23683, 11857, 8968, 1710, 21968, 2569, 2641, 27732, 12437, 11684, 3365, 3568, 30413, 31493, 126, 19692, 7640, 12087, 15012, 13810, 5820, 14835, 1663, 10615, 25897, 18677, 2774, 10134, 27553, 19533, 28878, 2286, 25624, 2734, 18075, 15349, 30293, 26984, 1518, 27792, 6504, 28822, 4055, 31708, 462, 24473, 20084, 24160, 2026, 26053, 19397, 11822, 19750, 21337, 13917, 4006, 4931, 22197, 27505, 151, 10357, 6599, 28290, 1898, 985, 21447, 1084, 592, 18725, 8996, 781, 32283, 15338, 17342, 30248, 30349, 1674, 970, 5506, 6767, 5053, 9793, 28505, 24146, 3609, 13924, 31335, 408, 12239, 26206, 24209, 15492, 16499, 18175, 1986, 23061, 13647, 15618, 25013, 26727, 15712, 27896, 21909, 27841, 20130, 9090, 9034, 7915, 6286, 31242, 29958, 1344, 3704, 22037, 5416, 5893, 1949, 1944, 30510, 22777, 29563, 26200, 14590, 32478, 28325, 17118, 25668, 10006, 9729, 24008, 14541, 225, 15536, 11980, 716, 1461, 15384, 28747, 32513, 30945, 6204, 30382, 7523, 26364, 1411, 16040, 250, 11504, 23483, 21766, 16141, 32067, 10845, 10506, 9088, 23256, 25107, 8266, 5857, 22678, 31090, 12674, 14155, 25191, 8990, 853, 32630, 10996, 8917, 29081, 3967, 1707, 8234, 28246, 32134, 19402, 8239, 3426, 30972, 31581, 8314, 10350, 4586, 5279, 17776, 25822, 6879, 3344, 15812, 5676, 3164, 7357, 3618, 30618, 24312, 10144, 16561, 28180, 18200, 1698, 21856, 18061, 29345, 5939, 19808, 9290, 17452, 979, 3682, 21419, 29928, 22284, 24547, 1046, 15675, 18613, 18709, 13371, 28642, 30069, 6336, 3698, 21501, 26034, 18129, 21358, 1436, 28469, 22897, 28504, 4798, 4202, 32702, 1238, 15032, 20065, 12516, 14481, 15579, 9023, 1727, 1771, 2411, 29344, 6140, 24816, 28488, 15319, 31844, 5513, 29801, 32250, 3379, 23283, 4364, 27038, 3012, 3184, 21759, 23501, 9574, 28733, 5059, 27714, 31348, 6595, 31153, 24541, 32440, 15377, 31681, 565, 19891, 138, 13310, 20967, 15055, 30063, 27224, 18222, 31711, 27441, 6648, 26804, 27834, 19368, 2583, 8872, 3812, 19974, 19176, 5137, 20633, 3241, 5745, 18018, 2167, 30682, 19252, 846, 8956, 25524, 6966, 15581, 8144, 3401, 496, 15296, 11876, 25027, 1205, 2018, 4291, 2810, 29189, 16191, 22471, 6259, 23700, 20217, 2016, 1943, 14624, 17064, 2685, 1157, 2684, 7666, 9275, 3231, 17632, 976, 6046, 29164, 6003, 13152, 31219, 8326, 347, 30691, 19649, 1547, 10405, 24346, 1025, 171, 14336, 4795, 29062, 32674, 5532, 63, 15896, 3210, 28959, 5692, 14550, 15290, 13795, 13852, 17350, 8315, 10036, 580, 30372, 9984, 8729, 2534, 6050, 31817, 16806, 1936, 25584, 10790, 31039, 413, 19066, 23116, 6388, 9425, 13101, 5610, 31093, 19982, 28621, 5193, 30459, 16754, 4593, 14895, 20280, 5638, 25167, 17420, 4345, 16883, 23865, 24696, 2087, 10390, 22632, 20189, 17839, 30831, 13817, 22129, 6753, 10679, 28928, 10600, 8252, 32106, 19861, 2151, 32011, 234, 7813, 14907, 828, 2751, 617, 11211, 25429, 2264, 15966, 19531, 1224, 10698, 19522, 2440, 27587, 15257, 23158, 4464, 13762, 8510, 2238, 2358, 31811, 13165, 5946, 13540, 27297, 8042, 14464, 23194, 12584, 10270, 4019, 3505, 1206, 29238, 2610, 28746, 8833, 7611, 19067, 415, 6645, 1490, 6354, 23448, 24919, 13079, 27988, 26321, 7592, 2920, 29086, 29751, 8652, 71, 31151, 14122, 26859, 7997, 10999, 1899, 4120, 1320, 3372, 16984, 4912, 29353, 23953, 19485, 20741, 10199, 11567, 4208, 6844, 1516, 1029, 4879, 21108, 17207, 5259, 25706, 23849, 24075, 28026, 20124, 27607, 17774, 2884, 20128, 24546, 3145, 20481, 11714, 20149, 24168, 13338, 20307, 26793, 23504, 1105, 1697, 18217, 15955, 32138, 2343, 26133, 3476, 679, 30176, 19555, 25633, 31816, 930, 10252, 19904, 20279, 12488, 24870, 28636, 26072, 3569, 26701, 15415, 18086, 4231, 17480, 19975, 1660, 20514, 8938, 16657, 14990, 19438, 387, 15447, 5242, 29481, 16070, 29936, 24061, 27219, 195, 20990, 12833, 8672, 30489, 21302, 502, 26928, 2143, 24898, 2871, 10945, 28406, 2222, 8686, 5794, 23577, 12844, 18683, 30608, 13240, 485, 16464, 3160, 20337, 16653, 27168, 28130, 32483, 1466, 4858, 22512, 1102, 3318, 13201, 32340, 21276, 2957, 4154, 10684, 15023, 1725, 26312, 8250, 13475, 20311, 26850, 19195, 5488, 11520, 26101, 28740, 24798, 29989, 18848, 6784, 1715, 12187, 14462, 28343, 18258, 16859, 8871, 14016, 8172, 22832, 24441, 17683, 16088, 31347, 29241, 18516, 18298, 39, 2771, 3205, 19997, 637, 5769, 23675, 29517, 9387, 15020, 6030, 17442, 21735, 3889, 20373, 3480, 12073, 10777, 786, 8381, 3292, 522, 18345, 20979, 31815, 15713, 2448, 19735, 2398, 2186, 16096, 20648, 2085, 14752, 521, 9260, 21982, 6636, 7688, 19919, 17236, 29908, 31176, 19278, 4198, 3028, 26386, 21011, 10976, 7547, 12121, 23202, 7245, 6702, 31648, 3081, 2572, 31598, 2370, 21920, 3201, 19359, 11080, 7298, 23391, 23960, 2063, 1145, 25867, 22033, 1675, 12136, 2058, 17775, 29813, 14376, 2819, 20272, 20703, 5086, 28868, 31942, 23542, 23495, 3566, 18456, 14186, 8437, 19198, 12626, 18364, 1085, 3244, 18908, 20340, 1360, 2814, 21154, 18012, 19752, 3338, 8706, 12525, 31862, 840, 23179, 3079, 32392, 433, 4113, 30392, 14145, 5991, 1969, 21839, 24308, 31923, 23762, 19473, 23681, 21970, 23147, 27053, 22708, 29313, 16715, 4429, 2680, 27689, 14663, 11771, 5541, 16259, 30444, 23572, 2514, 10966, 25988, 18170, 28168, 22199, 655, 3850, 31014, 12936, 16278, 19406, 1061, 10313, 29234, 4008, 23327, 17073, 23461, 2173, 9934, 2745, 25587, 3062, 3109, 6153, 26126, 20595, 1495, 864, 2406, 27370, 23859, 23305, 22496, 24833, 24223, 4852, 17879, 2180, 6126, 7793, 3249, 21465, 3037, 15444, 29990, 17271, 24087, 28099, 32561, 8596, 5715, 17552, 22492, 14753, 8257, 27590, 24959, 32208, 10886, 7809, 5865, 25686, 3705, 259, 22313, 2435, 31582, 4101, 10468, 22869, 456, 6731, 7578, 26074, 11395, 2542, 2974, 13316, 15024, 2214, 18585, 5722, 8971, 10057, 14095, 8174, 5038, 2183, 26658, 17295, 25722, 16983, 31747, 1220, 2232, 24300, 15590, 21480, 17408, 15505, 4426, 22858, 9818, 10557, 15561,\n24120, 5028, 23656, 25713, 3332, 23092, 17182, 26467, 11320, 7358, 21074, 3987, 9094, 4983, 21364, 27264, 19714, 26746, 31030, 10425, 26255, 13163, 3218, 5792, 14231, 31854, 2880, 4718, 16128, 19948, 4720, 9079, 3852, 3766, 28713, 5808, 12126, 14825, 2926, 17518, 3220, 10035, 3085, 25456, 24147, 31391, 1909, 3360, 751, 16208, 3257, 22294, 12589, 17524, 7976, 9694, 4090, 28742, 1159, 7419, 2090, 21702, 24844, 20523, 26539, 20609, 11827, 6637, 8186, 27416, 1827, 15169, 17623, 14899, 22514, 10415, 3644, 32748, 23669, 10378, 3485, 17858, 7952, 9846, 27137, 5915, 22988, 24616, 7288, 2382, 30061, 20333, 3915, 31271, 25656, 1886, 9616, 24524, 12129, 27442, 1984, 30967, 7049, 23396, 18026, 8582, 32383, 18775, 29029, 30276, 14552, 29504, 12755, 11417, 22844, 3554, 19443, 6824, 3846, 270, 121, 15733, 31351, 19917, 15793, 21873, 12060, 3031, 9074, 5985, 29973, 3482, 13208, 27395, 11026, 26720, 26291, 3854, 10929, 32338, 2846, 10193, 8, 12254, 922, 2750, 30157, 2692, 13803, 21090, 7912, 12289, 32399, 1861, 7299, 12322, 22902, 27602, 6369, 28300, 12729, 9734, 12438, 30121, 5226, 16463, 29, 22972, 24348, 16453, 32544, 2307, 25518, 18333, 27437, 20695, 13179, 661, 23144, 31699, 10961, 21907, 6576, 13472, 20645, 3592, 28103, 628, 24196, 6811, 15535, 15835, 1229, 3716, 23532, 24956, 16158, 31434, 24620, 23296, 19724, 13120, 24526, 16406, 8983, 3445, 2509, 21691, 26588, 2476, 20664, 18104, 29340, 20353, 2942, 17004, 2568, 14852, 15625, 17611, 27842, 8724, 3100, 30824, 13590, 10146, 31362, 23855, 27804, 3699, 16909, 19381, 31611, 1064, 10083, 692, 10532, 17312, 26099, 6161, 11047, 22405, 29720, 17569, 1932, 4602, 22139, 21228, 27580, 31661, 21778, 27440, 28427, 22148, 1427, 24745, 16125, 7210, 4698, 25616, 30875, 24815, 31748, 16226, 1465, 27479, 19593, 4478, 3005, 18536, 15333, 11105, 28236, 29110, 15638, 28010, 28037, 14518, 8399, 29367, 17508, 13896, 13438, 23978, 22638, 8245, 4059, 24169, 744, 27362, 24769, 11049, 26518, 16467, 10558, 4167, 29048, 25603, 9190, 22186, 1226, 3603, 28055, 21300, 3801, 423, 3382, 5396, 4566, 25230, 21665, 26152, 32600, 3617, 1216, 2830, 10668, 3643, 3626, 26224, 17728, 29921, 31693, 23425, 23267, 19312, 734, 452, 5169, 31299, 30599, 8211, 1296, 6890, 1711, 2064, 30563, 30592, 7545, 14767, 21754, 2857, 30980, 24565, 2015, 30820, 10273, 2815, 27579, 2915, 9388, 19269, 11886, 13830, 10809, 30744, 7321, 18319, 1968, 3714, 13020, 28999, 20454, 25893, 21984, 2357, 22999, 2432, 18829, 5950, 32181, 4505, 10365, 2334, 29488, 19094, 697, 3376, 2226, 23017, 1422, 15253, 16117, 4977, 19160, 21505, 32744, 24591, 6562, 3576, 4854, 32122, 11134, 23016, 25050, 9193, 31851, 1852, 20747, 4649, 8061, 6344, 31856, 498, 2885, 14439, 2718, 9107, 5268, 28155, 4189, 7432, 13799, 4162, 16735, 3242, 2792, 3916, 26182, 19029, 25316, 3059, 30353, 4583, 22399, 1135, 8357, 20070, 15271, 22342, 31331, 31432, 2567, 457, 17686, 29500, 28882, 15718, 23035, 32323, 30490, 16678, 25960, 101, 20949, 30400, 30686, 27626, 29838, 29991, 4841, 18938, 11593, 17096, 3216, 4493, 1953, 59, 2122, 19109, 2285, 20381, 21561, 29959, 5584, 25923, 31380, 16731, 11849, 25442, 8606, 6850, 32558, 26040, 22769, 9223, 31983, 27977, 12083, 3400, 11158, 15606, 16938, 19463, 20920, 18366, 15758, 19685, 28904, 20229, 19298, 1576, 5470, 23175, 28774, 1683, 9988, 32045, 2946, 4418, 8275, 2469, 25519, 14341, 26197, 8545, 1654, 7158, 14058, 32003, 23791, 13341, 24837, 1142, 31098, 12675, 19736, 17438, 9958, 2828, 30110, 15013, 5284, 5253, 20727, 2539, 2426, 19670, 14536, 3281, 23370, 6549, 1348, 9077, 26199, 16835, 3573, 30008, 8351, 999, 27617, 5233, 2842, 27376, 25529, 17731, 11044, 20342, 27793, 2278, 7528, 3196, 12634, 4999, 17757, 1524, 581, 13623, 15941, 7131, 15749, 32092, 9299, 25575, 32356, 14363, 29207, 14726, 201, 6424, 24083, 7389, 20735, 22024, 18895, 1049, 6170, 11483, 1024, 30131, 28365, 11324, 19773, 30051, 18255, 4468, 22070, 16843, 10030, 15756, 10765, 3114, 2980, 1458, 12358, 8124, 6008, 25311, 6667, 21717, 15928, 17590, 32632, 30694, 13870, 2990, 25412, 14000, 18064, 29726, 29097, 19682, 17911, 20106, 9868, 8644, 31590, 16436, 17366, 11592, 24988, 18838, 15865, 27212, 23947, 7446, 19659, 28873, 5771, 21256, 11110, 4417, 10666, 26250, 12670, 13145, 31688, 3514, 31199, 25774, 7043, 9429, 5536, 6763, 20016, 21858, 23934, 29628, 2061, 29146, 3815, 21174, 32178, 10139, 12082, 14024, 20900, 1575, 19337, 15376, 11300, 19424, 15864, 32604, 29732, 18525, 18629, 22851, 2185, 3192, 4143, 21706, 32063, 16071, 6490, 4288, 14819, 19979, 27195, 30288, 16807, 845, 15374, 31223, 21156, 14820, 2847, 9766, 27222, 22957, 553, 26271, 6955, 9389, 48, 8029, 3128, 2039, 1527, 20394, 8490, 2078, 28564, 5517, 24192, 4964, 12618, 3148, 24056, 22990, 2282, 28288, 32400, 21301, 21493, 1927, 269, 2839, 21033, 8431, 28085, 27845, 19026, 5842, 19080, 18616, 4961, 1173, 15907, 5920, 27704, 22166, 2582, 244, 2782, 27006, 6491, 4336, 30475, 22195, 29177, 11763, 32735, 23592, 14935, 19217, 27664, 5881, 13467, 26721, 16952, 17322, 1828, 31909, 429, 21424, 17699, 14153, 22151, 4282, 5041, 31874, 8383, 8720, 2637, 2882, 14077, 18213, 5202, 8658, 28912, 23753, 22249, 5058, 16575, 8090, 24638, 6823, 32745, 24701, 17205, 11558, 3123, 24287, 1041, 14026, 2530, 6209, 27585, 935, 27630, 12531, 25674, 27492, 8100, 23071, 28163, 15009, 6430, 22794, 1151, 11736, 27937, 5015, 2452, 26754, 9782, 17933, 25188, 17855, 11960, 30834, 9923, 3084, 14659, 28143, 5943, 15347, 31943, 21389, 4217, 21788, 3198, 12280, 32, 5261, 1813, 6860, 28592, 2404, 7271, 4742, 12344, 32135, 16448, 25636, 12353, 7549, 13888, 2823, 11825, 9251, 6190, 7639, 4619, 3362, 5775, 17624, 14078, 4985, 30564, 29580, 377, 26350, 6048, 29631, 18494, 20216, 28110, 2314, 16038, 31606, 1263, 31677, 15862, 29304, 262, 11128, 28334, 14329, 28312, 24082, 5389, 24986, 28934, 12735, 2140, 18666, 13632, 13485, 15822, 20003, 5161, 11896, 26141, 2150, 1047, 5872, 30828, 4770, 4932, 27165, 25645, 8120, 1810, 4752, 25970, 6621, 3596, 15004, 8514, 31678, 23210, 31705, 30505, 4869, 471, 16344, 11830, 6382, 27261, 26395, 27151, 30821, 83, 1354, 29320, 30799, 2295, 31034, 30623, 30130, 20284, 2557, 25812, 30193, 6341, 6575, 30760, 17525, 6611, 22167, 26982, 5783, 23387, 30806, 715, 19679, 18268, 3942, 3553, 29407, 20335, 12460, 24105, 21511, 24992, 500, 227, 7016, 8060, 29616, 3440, 1991, 2923, 67, 7300, 27225, 31917, 19140, 30301, 28749, 1807, 14449, 8491, 18760, 24382, 4836, 2916, 2968, 27333, 28544, 5519, 4809, 16701, 6631, 8324, 25807, 12725, 22301, 2992, 3969, 28610, 21164, 13963, 24124, 31476, 486, 2851, 13997, 23724, 2231, 20067, 2987, 20840, 28891, 24955, 16028, 1661, 27903, 18227, 2890, 32453, 5398, 22237, 4782, 24848, 24404, 7048, 25565, 960, 22133, 13175, 6241, 5257, 12147, 17362, 23954, 2423, 29462, 21658, 1721, 20784, 10688, 32404, 16116, 3611, 2936, 26429, 24537, 13629, 18389, 9843, 7004, 20101, 2148, 12920, 4753, 5136, 1820, 7582, 31766, 30077, 1472, 1966, 26958, 4179, 1759, 5987, 10823, 397, 11096, 16594, 8901, 17653, 14520, 3288, 28087, 20, 28643, 4953, 10824, 30660, 2849, 30976, 2732, 27447, 28751, 16966, 25690, 868, 2726, 22828, 29797, 14144, 2507, 9449, 18833, 12003, 22910, 3240, 21027, 15610, 527, 15282, 26393, 17187, 7863, 23961, 2565, 1418, 19251, 139, 12081, 3558, 927, 6358, 29317, 7178, 17464, 17457, 6572, 7221, 16922, 25756, 10867, 21260, 9298, 25343, 5234, 31346, 24019, 25352, 29205, 8411, 16811, 21793, 17405, 6881, 3651, 32326, 17898, 21271, 15842, 5694, 31712, 21535, 16500, 10955, 4013, 20323, 650, 6688, 28940, 4010,\n26017, 32118, 14948, 4077, 3495, 26419, 14648, 27860, 10171, 15851, 3695, 11223, 3637, 16649, 15800, 24407, 29339, 3765, 17177, 14812, 20641, 25304, 4496, 23162, 12537, 18551, 25851, 27205, 4457, 27819, 339, 29483, 31592, 14526, 2178, 15745, 6928, 4205, 15149, 32024, 5312, 9401, 25199, 24727, 5600, 22353, 705, 26542, 22567, 62, 12376, 14255, 26742, 16748, 3021, 22815, 14047, 11073, 1887, 4749, 32218, 5094, 14331, 7970, 29094, 8768, 982, 13178, 29293, 24981, 12695, 17586, 13929, 31905, 4278, 17859, 31119, 5089, 4900, 20238, 7054, 29061, 28654, 28176, 24171, 18147, 8503, 19511, 5126, 1772, 26107, 12205, 22599, 31802, 32366, 2004, 24435, 31321, 5732, 31820, 32324, 27733, 18367, 18899, 21054, 10167, 19212, 26114, 3101, 5793, 11977, 2829, 29125, 6831, 14889, 23326, 5627, 29329, 2489, 2657, 29244, 6612, 24387, 11957, 15503, 19491, 10482, 27024, 19, 13361, 952, 8496, 29456, 15183, 15597, 11554, 25032, 18102, 31509, 30687, 30752, 9081, 31738, 4630, 640, 1352, 22602, 15369, 3282, 19989, 14437, 21599, 35, 3179, 19654, 24652, 23399, 1371, 29676, 27912, 5293, 21871, 2649, 22590, 28281, 5206, 32144, 5319, 27934, 31868, 20228, 28294, 2704, 8785, 23774, 19184, 6651, 18884, 31980, 10915, 15189, 11681, 19074, 13759, 5850, 4546, 2310, 6427, 31893, 9421, 3161, 873, 9546, 21350, 21263, 16461, 21846, 23458, 9594, 434, 27459, 13502, 8246, 20420, 25254, 7953, 15760, 29354, 25419, 1808, 16616, 20113, 13335, 1669, 2096, 9265, 9370, 31669, 26525, 12746, 17644, 19512, 28054, 27923, 5105, 25726, 23201, 773, 25306, 3080, 4687, 31914, 30030, 24214, 3223, 28985, 2700, 18849, 2322, 13285, 6762, 30645, 1268, 21374, 5152, 23848, 2345, 1749, 22762, 1350, 30579, 1792, 12200, 26343, 17519, 7481, 3370, 8991, 2267, 19984, 12714, 210, 31555, 30653, 32436, 14386, 249, 2650, 32151, 28552, 25516, 1743, 17888, 9499, 12425, 26983, 909, 25331, 9814, 11502, 5970, 19537, 17598, 4224, 27267, 6851, 11888, 14463, 2205, 28694, 15741, 29934, 30416, 2812, 14081, 9695, 19618, 33, 25094, 27743, 2538, 7121, 1445, 29967, 8243, 12365, 28243, 17135, 16937, 4599, 4673, 13192, 30512, 19124, 31, 1245, 27242, 31843, 2738, 13818, 21875, 1692, 13910, 18361, 13132, 19728, 3712, 30327, 469, 5019, 28111, 31614, 17777, 22338, 15175, 18944, 30182, 27178, 19821, 6340, 3640, 7966, 2287, 8148, 17547, 9951, 12907, 19551, 3110, 6557, 291, 13009, 27034, 21576, 10540, 26023, 22574, 15454, 369, 11906, 5709, 24999, 1274, 23930, 573, 28287, 25816, 8884, 29863, 20031, 22604, 9783, 31198, 25422, 8010, 20987, 5604, 568, 31918, 30759, 24023, 25709, 4903, 30901, 2533, 8477, 14023, 523, 8828, 11435, 31306, 12517, 9009, 1000, 4125, 1265, 21590, 12891, 3631, 1538, 30792, 13776, 5478, 10991, 12693, 23409, 11620, 1468, 22662, 29206, 31344, 6034, 10842, 18440, 10089, 2773, 22642, 4901, 21486, 6146, 1248, 11486, 1271, 4230, 9466, 21474, 28065, 11788, 17349, 15827, 4248, 4799, 27741, 14246, 32474, 584, 16114, 31628, 32276, 23673, 14943, 12312, 3232, 14883, 13239, 30997, 5899, 28518, 27483, 21987, 18795, 27540, 1912, 1956, 4253, 30625, 1479, 13207, 4552, 3954, 30399, 13940, 2043, 32739, 23412, 14377, 26623, 11472, 11983, 3885, 3020, 18720, 16257, 14702, 27865, 10606, 12276, 25924, 10652, 30213, 19035, 1699, 28298, 1890, 13367, 19606, 11221, 30279, 28169, 27854, 27927, 31536, 24258, 27486, 21531, 31284, 5142, 6066, 26162, 15689, 15923, 29690, 25342, 9282, 31277, 12180, 19969, 32654, 18715, 16051, 24736, 11755, 15174, 18477, 1154, 24729, 10882, 27126, 19769, 11237, 1685, 15676, 13604, 460, 24161, 21197, 8595, 32316, 5485, 15062, 31602, 955, 7718, 2470, 8079, 8709, 9662, 10224, 11574, 7682, 7475, 28409, 2749, 31040, 29163, 14568, 6094, 4361, 5472, 25286, 28986, 6089, 5567, 4604, 30562, 25594, 9076, 598, 18604, 23533, 468, 4609, 4843, 2964, 3044, 11014, 29618, 14996, 16873, 7148, 29992, 31260, 27712, 30578, 16866, 25589, 4020, 23355, 29588, 1694, 5081, 31087, 5271, 9228, 4621, 13454, 10309, 27472, 4690, 13991, 13739, 24853, 31676, 12567, 17054, 3336, 22490, 4658, 19056, 10773, 4053, 327, 1002, 2896, 12888, 10539, 17585, 21841, 27975, 5520, 11560, 30846, 14581, 3859, 26650, 11989, 264, 13403, 21960, 21462, 8732, 20392, 329, 14063, 16923, 14611, 24740, 28035, 22443, 22270, 3919, 2344, 26112, 20576, 11845, 2486, 3056, 2104, 31544, 16498, 2508, 12878, 28412, 6723, 28002, 22411, 4193, 23117, 31583, 1227, 4514, 25290, 28875, 20801, 3857, 16544, 20236, 20012, 16274, 5433, 29346, 24401, 28534, 21135, 29072, 27857, 437, 5665, 2109, 3671, 8722, 798, 32716, 24540, 2906, 10282, 1848, 20366, 23290, 3227, 14458, 5616, 30865, 6305, 30813, 25434, 1770, 9555, 8507, 4299, 7730, 4075, 8803, 21439, 26194, 22488, 2224, 28728, 32120, 25358, 2280, 6052, 19764, 23713, 24013, 12452, 28374, 24978, 29964, 12704, 31897, 27558, 10377, 22837, 2115, 19459, 20432, 20955, 22105, 20526, 5937, 1366, 3914, 23155, 19290, 6446, 18182, 19635, 20093, 3936, 15846, 21238, 5456, 24403, 28254, 25599, 3641, 6925, 18074, 12324, 10344, 3468, 13749, 30469, 10597, 14334, 16647, 22426, 20043, 28420, 13592, 31494, 17269, 5175, 32296, 28690, 19481, 14471, 3890, 16713, 1290, 16030, 10806, 736, 29360, 2688, 5314, 26950, 6391, 4736, 606, 391, 2093, 13196, 20583, 17950, 17557, 7435, 12, 27672, 10869, 10165, 30351, 4620, 1439, 2516, 31162, 4515, 3770, 24243, 30583, 2497, 1367, 11091, 30942, 18563, 9125, 7007, 18370, 15121, 31468, 2658, 24336, 18275, 1221, 11576, 1799, 29837, 14241, 2284, 5712, 3884, 23635, 23263, 17830, 28346, 26540, 27337, 4714, 27650, 3339, 23705, 14670, 15940, 27656, 2080, 7728, 27421, 32673, 13, 13124, 4692, 9354, 2400, 5494, 4261, 29006, 17554, 20700, 6005, 3418, 5334, 16794, 21026, 20463, 528, 5458, 30494, 21351, 20199, 3, 18442, 19280, 10016, 28028, 15098, 30286, 1730, 8553, 3274, 23262, 444, 21649, 29156, 7055, 12572, 12889, 2858, 28324, 129, 31586, 27443, 8046, 27825, 5044, 32617, 25936, 7473, 29906, 333, 8756, 11051, 31548, 16534, 23931, 22322, 829, 8202, 11176, 21580, 13269, 5388, 3429, 15885, 22002, 31386, 16327, 14274, 5760, 99, 25042, 3055, 32689, 4832, 4928, 24572, 3054, 27703, 2570, 28207, 26201, 5362, 4088, 1997, 11652, 19175, 25750, 10678, 30891, 20893, 10630, 29197, 9531, 10489, 15165, 4521, 30458, 9964, 440, 32231, 4183, 22710, 20488, 13763, 4118, 8188, 23821, 17264, 28809, 9754, 14722, 27850, 5854, 6586, 233, 9524, 15818, 1113, 3932, 6472, 27798, 4497, 18341, 2574, 6500, 25566, 29969, 5754, 1552, 850, 31593, 13226, 23486, 31685, 7737, 2730, 17901, 22749, 15967, 3935, 4265, 32503, 5679, 16710, 14508, 328, 26279, 10184, 18121, 29307, 26192, 29636, 5217, 6337, 24972, 10518, 2073, 29003, 1281, 2662, 1850, 2068, 9451, 2972, 8804, 29343, 28179, 21564, 10504, 12837, 11453, 30100, 16333, 32182, 789, 5413, 31279, 13257, 88, 6129, 20297, 31327, 31957, 1778, 15343, 5876, 30317, 31428, 15648, 13613, 253, 28540, 9693, 6332, 1339, 1814, 5489, 216, 23212, 6834, 3849, 6147, 20912, 10141, 23209, 1349, 9180, 32065, 31353, 4562, 23365, 25111, 12817, 11011, 763, 29839, 6516, 13345, 5355, 30487, 30963, 18664, 14442, 1361, 15833, 4655, 6502, 31948, 1481, 29987, 11007, 9006, 30659, 21129, 28724, 21070, 29485, 27104, 17541, 3992, 28230, 22715, 20944, 22178, 7658, 5384, 7738, 31481, 4638, 32271, 13635, 32263, 19782, 6262, 6028, 2021, 22425, 17752, 9204, 5446, 19412, 13004, 8045, 27536, 1244, 2549, 954, 8529, 20132, 9, 22316, 2429, 7761, 9133, 12930, 10746, 28793, 25283, 4845, 4412, 21880, 8835, 24987, 20570, 26560, 7629, 5560, 3502, 26391, 31217, 28249, 28386, 18621, 29953, 26912, 10713, 22334, 16999, 13137, 25615, 14164, 6053, 23511, 27508, 6846, 20943,\n6737, 32507, 27016, 12251, 24351, 30878, 16052, 30437, 24420, 28587, 14360, 3778, 15273, 8034, 26104, 28980, 9301, 378, 25387, 29080, 13500, 6615, 12709, 24072, 25061, 19952, 10970, 22823, 27662, 6566, 22050, 1610, 27431, 12978, 26507, 7161, 4821, 27864, 22298, 27002, 16933, 29451, 29193, 21072, 7468, 8703, 12864, 4892, 1849, 9050, 2696, 28758, 22444, 12155, 513, 768, 8885, 4358, 25944, 9847, 6666, 29396, 14535, 26549, 2428, 17633, 19351, 29823, 18625, 27026, 15346, 3200, 20838, 104, 26649, 3217, 23624, 32031, 14815, 31849, 8352, 12019, 6070, 31505, 8919, 28826, 24487, 7030, 22345, 29796, 2134, 5790, 31653, 21685, 16115, 25321, 26079, 2638, 7804, 25573, 10733, 11452, 30616, 12229, 30253, 22159, 9983, 5772, 3845, 13950, 6826, 8591, 30894, 23213, 22371, 11986, 14662, 15190, 27806, 21906, 5418, 21622, 1841, 29893, 16218, 27317, 5085, 9566, 30557, 23279, 4628, 4867, 21345, 31187, 17430, 4155, 6025, 1534, 31457, 5972, 16235, 10287, 2535, 32749, 3348, 16624, 6838, 11918, 12800, 17244, 6431, 9086, 26840, 11508, 21753, 11597, 23192, 5278, 28436, 8907, 28814, 5022, 20561, 32376, 22052, 5251, 1523, 3132, 28075, 1149, 15061, 2636, 30667, 12300, 2, 3410, 2129, 24612, 13682, 23876, 6157, 5289, 28492, 31029, 1776, 30380, 20842, 19131, 26459, 8700, 11638, 30923, 28072, 2545, 29879, 4363, 14141, 30890, 20834, 5832, 6470, 23082, 10000, 14560, 26497, 6141, 16099, 28923, 29581, 6833, 30676, 3038, 28556, 30797, 10319, 5984, 1326, 4385, 24417, 3616, 8125, 26214, 11410, 2686, 26885, 26547, 4969, 5344, 2827, 14643, 10155, 12464, 14537, 5558, 31055, 16911, 3650, 19947, 31722, 9129, 827, 14080, 85, 8764, 7234, 17076, 31995, 4365, 13384, 24847, 28481, 20547, 5555, 10832, 1035, 5092, 27775, 27884, 5859, 27294, 2059, 15653, 7701, 3104, 4404, 15729, 19215, 26232, 25763, 25532, 3083, 3990, 18296, 24439, 31168, 12238, 5241, 20803, 6006, 22620, 6950, 7849, 19205, 4524, 25078, 11787, 27906, 12629, 30473, 7898, 19973, 27986, 27620, 21002, 32196, 24485, 15063, 22211, 20066, 18827, 9583, 3930, 867, 30479, 29112, 8831, 2541, 26457, 11812, 3256, 15802, 1448, 6513, 439, 18497, 1379, 3215, 12293, 6225, 28425, 18418, 16338, 22424, 70, 11183, 6345, 9328, 386, 7483, 19221, 27111, 26917, 5681, 10923, 31781, 15905, 15847, 25731, 2786, 1323, 14409, 10234, 12500, 1970, 30201, 21157, 5668, 3856, 4485, 27527, 5372, 4733, 7087, 11383, 9827, 24499, 3061, 22090, 26828, 12100, 27197, 934, 10906, 6885, 17245, 13209, 202, 19981, 20939, 9699, 4471, 9407, 4567, 5592, 27457, 11427, 3731, 25560, 27259, 15452, 24800, 603, 29359, 26851, 6875, 11569, 29158, 16990, 27279, 3946, 7857, 11319, 11875, 24149, 32525, 25610, 10798, 19467, 32414, 20509, 4480, 4880, 7981, 23207, 7719, 6543, 27022, 26654, 20770, 6423, 6920, 12355, 24232, 5765, 18618, 30543, 16237, 2681, 709, 5122, 6964, 6471, 12541, 4301, 27438, 17427, 567, 2910, 19696, 14824, 19683, 5529, 10640, 31910, 19570, 32167, 23535, 20903, 19445, 29473, 15414, 473, 22917, 11630, 31744, 12432, 32139, 24090, 18461, 132, 6635, 21517, 1097, 9321, 1818, 21805, 4333, 4721, 15246, 4970, 15788, 855, 27778, 17227, 26024, 30704, 5675, 30378, 20050, 14642, 19254, 4789, 1390, 18724, 28936, 5840, 14754, 3171, 14022, 32555, 17267, 22509, 2410, 11872, 16552, 15874, 16977, 13697, 32081, 9941, 31442, 12341, 28723, 24968, 25065, 1816, 18655, 16727, 1412, 8283, 2137, 30450, 1051, 1162, 12882, 14035, 3098, 25135, 8930, 28776, 17520, 27950, 4200, 32372, 1148, 25233, 5603, 17125, 6122, 12782, 20760, 17065, 6452, 2787, 5423, 23322, 4486, 3435, 14638, 8631, 1565, 6426, 4362, 32359, 8378, 14419, 6387, 8741, 25315, 13076, 21168, 31637, 27915, 19587, 20531, 30062, 29567, 20552, 1378, 30911, 20781, 3742, 9118, 2900, 4254, 24234, 162, 10680, 9790, 29290, 17399, 8168, 27568, 19634, 31157, 7544, 2444, 5275, 20800, 25219, 5088, 16349, 3519, 7580, 29465, 21448, 30159, 31485, 3710, 23340, 26849, 9770, 19297, 21433, 15140, 2622, 14545, 5540, 27746, 18250, 21082, 3838, 2691, 25531, 17730, 8396, 25446, 16331, 30743, 26868, 25409, 13139, 29064, 32693, 6676, 10143, 5162, 17973, 1724, 27012, 26532, 1977, 20433, 10843, 5286, 30297, 21298, 11471, 8937, 11261, 12809, 27786, 23586, 17327, 31177, 9053, 3323, 7155, 5491, 24597, 7099, 31394, 21823, 31830, 26466, 2213, 23993, 15090, 21653, 21234, 29999, 24247, 6755, 2065, 10745, 619, 23488, 3022, 23377, 26881, 30165, 28719, 20805, 2794, 7646, 25740, 13441, 5746, 1756, 21797, 12066, 6460, 20391, 5236, 26266, 1270, 27227, 27998, 16396, 31148, 2932, 2615, 32736, 17015, 22893, 19323, 28606, 1124, 4218, 27576, 26891, 31413, 1843, 2698, 28064, 22729, 1494, 24037, 24195, 3830, 32460, 5300, 1701, 10794, 18561, 13303, 14992, 13959, 4948, 19206, 14613, 3670, 15639, 19455, 6561, 2651, 4410, 7384, 16576, 22539, 32339, 25364, 6936, 27719, 6849, 26755, 13912, 29297, 5714, 5371, 16808, 27941, 18981, 13156, 23298, 4874, 6871, 29519, 19466, 2172, 19448, 1123, 13531, 10204, 29611, 2029, 29630, 30513, 1951, 7320, 6338, 21845, 31810, 30368, 6328, 25416, 6100, 14399, 21567, 7046, 759, 8941, 983, 852, 4898, 10974, 27013, 31243, 6020, 16145, 32434, 13659, 9324, 767, 32681, 3968, 15927, 2094, 10849, 6565, 4312, 17923, 31566, 5417, 15411, 17368, 12048, 15781, 23833, 10574, 24688, 21884, 7668, 28307, 2425, 26148, 6630, 5708, 14960, 6700, 23922, 19951, 1492, 10342, 630, 3425, 10430, 19451, 17720, 10198, 3327, 6281, 24405, 21382, 26861, 21614, 16612, 25214, 27601, 4009, 14938, 25005, 1678, 16666, 6985, 26906, 25579, 28706, 29619, 29180, 1935, 12733, 23251, 10724, 23076, 15292, 8159, 5778, 15596, 9527, 10807, 30387, 12027, 1920, 10805, 11127, 27758, 4547, 16583, 9803, 28124, 32239, 21341, 5635, 3465, 30183, 22278, 4927, 16434, 4711, 22229, 8853, 21930, 5408, 14730, 32543, 21632, 19141, 28992, 15416, 3063, 25545, 18815, 26876, 1373, 17974, 1741, 21885, 1408, 32652, 19748, 23085, 25172, 4974, 8171, 7380, 2277, 24796, 4172, 30266, 20731, 8987, 11670, 3525, 26158, 25689, 21727, 13746, 19688, 5352, 9197, 20989, 17895, 398, 4951, 12018, 19373, 26663, 32570, 23873, 30140, 3068, 26392, 25945, 11859, 26608, 2502, 22839, 17583, 13518, 9159, 21518, 27974, 6167, 31248, 28457, 27880, 1143, 7193, 17882, 2796, 26929, 30770, 14557, 3780, 18554, 3078, 29537, 16868, 24521, 25618, 29932, 26381, 32522, 13419, 14345, 26169, 31345, 22216, 895, 23239, 23725, 25779, 3475, 27172, 20421, 8716, 21762, 30200, 3157, 4738, 32413, 4605, 31483, 3799, 25716, 7363, 13253, 30995, 29228, 745, 5544, 3310, 18593, 27369, 13362, 5606, 3666, 28500, 6219, 21671, 1635, 7571, 31981, 25940, 24014, 2914, 3212, 7507, 22622, 8327, 32008, 20320, 1982, 19898, 11271, 18386, 2192, 8552, 16217, 31214, 14988, 693, 15089, 28474, 22414, 12296, 20268, 30478, 357, 29949, 2746, 11568, 30921, 25130, 4652, 26456, 7237, 30428, 4916, 25298, 4549, 12546, 19039, 29753, 5027, 30515, 11431, 7494, 691, 31460, 2845, 1121, 4416, 7774, 17056, 29118, 6872, 6764, 1008, 6896, 30917, 15132, 32384, 6822, 5779, 4, 25491, 30256, 26370, 18519, 4868, 5216, 7901, 8361, 4255, 23966, 1974, 31454, 362, 14780, 3869, 4780, 23289, 21713, 4941, 3279, 29444, 28304, 12840, 5291, 12135, 15632, 19582, 31239, 13250, 12644, 8852, 27170, 32009, 7338, 27552, 26908, 21894, 10419, 32621, 30244, 30044, 16782, 2591, 17436, 16825, 21052, 25060, 24, 5845, 13296, 31610, 23773, 4847, 4305, 16677, 28918, 21111, 5281, 11650, 11570, 21980, 26681, 7426, 1459, 31267, 5797, 6118, 17718, 3777, 30285, 16065, 7260, 5822, 4371, 1287, 26155, 1987, 5356, 24885, 5625, 30909, 7780, 6367, 2242, 17148, 7714, 29609, 15620, 4617, 29966, 9624, 11781, 26057, 12706, 26508, 7482,\n12547, 4458, 27397, 1905, 5118, 1606, 8414, 15601, 29597, 18294, 1967, 2189, 27339, 10039, 16163, 28734, 9774, 18444, 6150, 27341, 8080, 26770, 1979, 20449, 14086, 15674, 1257, 14185, 6376, 31829, 12275, 26090, 31294, 2211, 15037, 5438, 8962, 16591, 5199, 31377, 13612, 4870, 16876, 7276, 19958, 15171, 24191, 23248, 7303, 12698, 22550, 5758, 5728, 27635, 23742, 7438, 11860, 11473, 24477, 11493, 695, 15404, 17213, 10032, 5525, 31257, 27066, 4421, 5848, 168, 3287, 29910, 3296, 14838, 19232, 32303, 5546, 23566, 5643, 17262, 18534, 30240, 29868, 14694, 6102, 17011, 7733, 10642, 2269, 3834, 3547, 9730, 1503, 6267, 26365, 10411, 3526, 14737, 31161, 31038, 30031, 8117, 16317, 11999, 12151, 24991, 7538, 6782, 23454, 27077, 12012, 3912, 31209, 23837, 22174, 7091, 6057, 23718, 1851, 30516, 6876, 1106, 28722, 3486, 29508, 8001, 28516, 7747, 4728, 3029, 9921, 27582, 15863, 29806, 9488, 29831, 16714, 28844, 31694, 15082, 25736, 3839, 12619, 27983, 19647, 19362, 12406, 24560, 4033, 6187, 12561, 22720, 24380, 17441, 6550, 26111, 21738, 2414, 30015, 1005, 32251, 2989, 32281, 1482, 401, 653, 23380, 31971, 27244, 12606, 23058, 19787, 7356, 6327, 11430, 17622, 10747, 13407, 24296, 23714, 7205, 263, 15406, 18810, 12515, 21935, 6907, 7785, 18334, 29569, 25001, 1476, 9963, 14177, 15726, 29634, 11707, 23529, 9266, 23627, 28764, 19900, 3248, 30590, 17530, 7757, 21413, 19096, 17016, 8092, 2248, 7251, 31007, 13730, 3050, 5547, 4452, 22255, 14684, 8535, 594, 29781, 7790, 18036, 10047, 8505, 10607, 3278, 4958, 16281, 17746, 5663, 14422, 24592, 6413, 12808, 24052, 3411, 29938, 2948, 16924, 10657, 6708, 23946, 5335, 2010, 2263, 1627, 17831, 6441, 8062, 10637, 29899, 2023, 10909, 7138, 4654, 25698, 6988, 8827, 2372, 19046, 2139, 1234, 8081, 898, 19792, 15221, 18697, 30727, 813, 6206, 32765, 25007, 351, 4816, 20194, 16238, 23988, 30231, 31827, 421, 15980, 25743, 2383, 11099, 4756, 28205, 2466, 23668, 9359, 6395, 31572, 3354, 15094, 24332, 21866, 1888, 15266, 9463, 2346, 17431, 1286, 13360, 23166, 3887, 4561, 27691, 13883, 22173, 14966, 15706, 4391, 2474, 10708, 25929, 23670, 10820, 22266, 28478, 21378, 13927, 23038, 4340, 13359, 3225, 11978, 4030, 27361, 20191, 29328, 28807, 1444, 2809, 30156, 6040, 7992, 28864, 647, 10150, 15225, 29639, 4857, 22969, 9740, 16001, 30007, 305, 9526, 32059, 7346, 16979, 22966, 24478, 5345, 29053, 18886, 396, 14720, 24788, 26521, 4442, 856, 28284, 27106, 6817, 10795, 3709, 8799, 5999, 3795, 4246, 21252, 21367, 24140, 18103, 10855, 16755, 11052, 16856, 8445, 7776, 29161, 6166, 10789, 28908, 4705, 19127, 4447, 14427, 13503, 1276, 14265, 6675, 5246, 19781, 17803, 1345, 24263, 22760, 9316, 8115, 13777, 8069, 21828, 4784, 22703, 4444, 6017, 18374, 7651, 7535, 4402, 13935, 4441, 7334, 5942, 29167, 21414, 31387, 21857, 12912, 7859, 27643, 17691, 28720, 25782, 25815, 3144, 12133, 4511, 32304, 29747, 5231, 23206, 19098, 7987, 17619, 16791, 32370, 10467, 29162, 5509, 2071, 6975, 4653, 7694, 30678, 5465, 14762, 27427, 27990, 17460, 26893, 6173, 29335, 9122, 26166, 23948, 7151, 5119, 5138, 5466, 11373, 6347, 26061, 9341, 7693, 4149, 10406, 7521, 14268, 29696, 6065, 6619, 10127, 18571, 13114, 18042, 7750, 8362, 1728, 24746, 9977, 4353, 14025, 24861, 20465, 26764, 13953, 29821, 11626, 6778, 165, 16545, 25357, 15780, 31124, 8011, 5815, 11347, 20723, 4716, 4699, 31079, 31768, 14426, 6440, 30468, 21291, 9029, 5342, 21598, 14978, 13727, 12825, 20460, 1919, 5180, 12223, 17347, 6402, 22165, 25399, 15423, 14055, 28152, 8807, 18809, 21330, 6091, 18111, 26450, 9344, 3075, 17689, 23205, 27744, 395, 11217, 9856, 7722, 25479, 26435, 21650, 12088, 30307, 21067, 15778, 27543, 3843, 9048, 5932, 27779, 26091, 31626, 24915, 19616, 7548, 10980, 12166, 21661, 1186, 13933, 3929, 24085, 15250, 891, 31004, 23288, 27015, 28494, 24057, 12559, 4534, 6910, 25179, 21290, 21241, 10264, 29896, 5788, 2407, 5864, 25335, 26437, 26108, 20158, 25700, 31292, 20042, 29115, 10163, 25424, 6396, 16250, 32203, 26586, 5409, 4840, 31931, 13437, 1038, 6059, 18001, 17041, 9845, 23630, 27074, 10400, 8993, 2054, 31180, 4950, 5542, 1872, 8318, 8581, 2643, 21827, 18201, 4502, 19023, 12038, 26966, 23834, 28763, 30371, 32581, 4732, 11456, 32644, 11210, 29089, 12593, 4477, 23792, 27191, 6990, 30519, 2775, 30284, 12069, 7167, 27268, 1835, 4306, 26544, 29691, 21069, 7573, 11444, 28200, 4195, 23336, 6183, 24299, 4316, 28913, 27158, 16764, 9948, 803, 13772, 7008, 13790, 4956, 5047, 831, 4888, 7499, 6710, 7467, 21814, 27428, 15467, 15605, 5511, 22383, 465, 26351, 4826, 24661, 11929, 7440, 32502, 4359, 13886, 32128, 9047, 22153, 30503, 24281, 21605, 4709, 22971, 2300, 7242, 2332, 4674, 8253, 23225, 29229, 7554, 16588, 5351, 17252, 15857, 2706, 20975, 3273, 11351, 1947, 30741, 26708, 2595, 72, 17290, 7070, 13717, 32146, 23760, 10756, 4092, 26872, 7057, 17032, 26898, 32586, 29468, 7933, 20444, 6721, 31027, 18025, 8232, 4000, 22332, 23022, 9145, 5926, 17709, 20895, 30501, 29585, 9319, 7513, 7136, 27488, 16244, 4865, 12490, 3375, 6546, 6326, 936, 14565, 18962, 7059, 3719, 31197, 9982, 8113, 25122, 29157, 766, 7633, 27566, 18321, 636, 24973, 17995, 28081, 27787, 32562, 26729, 8056, 6133, 5477, 28624, 57, 1335, 20461, 31453, 2577, 18916, 3163, 26538, 23378, 29093, 17334, 9588, 5424, 470, 26769, 14115, 366, 28006, 15232, 19874, 19078, 4337, 16800, 12848, 24609, 5958, 16757, 23671, 19058, 624, 29357, 7009, 8651, 1766, 27095, 20204, 19602, 5147, 8087, 8643, 5069, 22978, 29549, 8580, 1072, 12473, 2119, 32309, 26918, 31444, 571, 1152, 7782, 4321, 14616, 10223, 12712, 11186, 3141, 4766, 27467, 268, 4433, 10876, 4662, 19946, 16981, 11753, 4704, 10838, 8597, 4322, 19595, 8911, 21115, 28593, 28013, 237, 26765, 5578, 26265, 1864, 20566, 26556, 3928, 9365, 2755, 7184, 25356, 1108, 26920, 12000, 25784, 4389, 1409, 1419, 8957, 7817, 418, 27322, 13686, 7943, 5035, 3112, 8231, 29202, 17049, 28693, 20401, 21435, 3546, 3983, 17576, 27155, 21708, 90, 1164, 31682, 19725, 14107, 5883, 2449, 2377, 1094, 1417, 15355, 1207, 29392, 29384, 8611, 32606, 18403, 31935, 25487, 13041, 5660, 1273, 25282, 7189, 22032, 7223, 7787, 18178, 6795, 7560, 11137, 24536, 2463, 22177, 5863, 10203, 21913, 2895, 15314, 14099, 22998, 8103, 16598, 20117, 24201, 941, 17374, 28788, 6524, 14106, 29491, 8848, 2006, 28861, 8235, 27570, 32661, 15471, 3291, 2030, 18920, 16845, 32541, 20759, 20598, 7135, 22808, 8372, 2066, 26823, 13505, 31384, 3390, 15311, 24252, 20017, 6506, 28306, 15543, 20848, 24594, 30355, 20057, 18863, 31978, 28206, 14668, 24770, 23386, 12610, 26273, 6339, 10813, 1283, 8358, 30035, 25295, 31192, 8875, 6372, 4876, 27298, 7559, 6686, 2142, 19077, 14784, 19275, 31438, 2113, 14840, 16048, 26038, 30390, 8775, 24493, 31988, 26394, 1591, 5150, 4142, 8086, 3734, 1452, 25432, 25693, 30219, 3356, 4855, 15304, 22378, 1391, 28755, 13260, 2725, 22826, 4289, 31974, 27128, 27632, 24409, 28823, 15719, 27055, 18614, 9428, 6487, 25223, 8026, 30872, 17727, 21709, 24578, 20565, 147, 29759, 14473, 18976, 21750, 8653, 11953, 15229, 4509, 5343, 18600, 18771, 13611, 8778, 27627, 16188, 1568, 15002, 17960, 6968, 30000, 28816, 12360, 29217, 22385, 4001, 27391, 11619, 22946, 2824, 16696, 12389, 6894, 7019, 7335, 25030, 18627, 6307, 25551, 19295, 8874, 23643, 31853, 12747, 7965, 25322, 6512, 8754, 15953, 21792, 12110, 12197, 497, 31991, 4112, 25652, 28988, 27289, 11231, 23034, 4743, 414, 6438, 20656, 13265, 3483, 4717, 19924, 28475, 18972, 20802, 13652, 27299, 13580, 10925, 20380, 16708, 13599, 27075, 2128, 4990, 28955, 8095, 29134, 3559, 14658, 5140, 3156,\n26094, 77, 29673, 12959, 10530, 4905, 2676, 2417, 10638, 24554, 27394, 10276, 32456, 25232, 12328, 2722, 29063, 15385, 4139, 27816, 3018, 4487, 11304, 14368, 2690, 12975, 4813, 1183, 10391, 31887, 32415, 26139, 23733, 24479, 11773, 4906, 8513, 22495, 552, 18835, 31541, 19652, 23171, 18595, 26724, 7273, 28517, 5784, 24142, 21163, 11612, 10474, 13649, 31435, 30670, 1720, 583, 13833, 3127, 2045, 1330, 21985, 8322, 9772, 28609, 3771, 12793, 11696, 14373, 22061, 26715, 24141, 25308, 16739, 31138, 13497, 30251, 26398, 19289, 3772, 5693, 26474, 12999, 7478, 7366, 5965, 6998, 6352, 13567, 3577, 13854, 4815, 26066, 3965, 8590, 23956, 29849, 26892, 2548, 4252, 6814, 11881, 8347, 4670, 5221, 22318, 18098, 21967, 7972, 3572, 6067, 29586, 23797, 1789, 24413, 32227, 29226, 30572, 16812, 8434, 30169, 17575, 24874, 21890, 47, 7385, 25420, 32361, 6484, 2042, 6214, 4564, 11500, 10298, 26596, 280, 6776, 14923, 26496, 7460, 5274, 22677, 23023, 260, 18764, 31825, 24820, 25591, 12919, 12855, 297, 15727, 4665, 10300, 21888, 14969, 21813, 30373, 26041, 20359, 3280, 20456, 2037, 2243, 8428, 3913, 420, 16882, 3032, 23266, 16387, 20631, 7906, 28921, 15380, 25912, 16702, 27078, 9653, 8594, 4677, 31779, 4406, 17802, 29834, 19168, 27969, 371, 1137, 3092, 772, 7862, 5320, 3564, 9019, 4685, 26677, 13117, 32165, 19763, 10648, 4403, 18667, 5426, 7620, 213, 25676, 15707, 12075, 3266, 16729, 18482, 29466, 30665, 12494, 22571, 28990, 31512, 4443, 5633, 25947, 19224, 16778, 4594, 6525, 18740, 8303, 30294, 26290, 3058, 18589, 12270, 24633, 3415, 4788, 21563, 29860, 25622, 19514, 28276, 6554, 22711, 17375, 18284, 30966, 6258, 23564, 14394, 32374, 3642, 12415, 14096, 4344, 29528, 7397, 7401, 31103, 29295, 26417, 8795, 31015, 25082, 3673, 24222, 18388, 24275, 25123, 22372, 7290, 1396, 4682, 771, 2585, 19529, 25881, 1447, 32718, 3939, 24763, 19615, 2072, 793, 14712, 1260, 13631, 28531, 17454, 7971, 27596, 2209, 28832, 20925, 1289, 2431, 18964, 29715, 30929, 21289, 19207, 29629, 28167, 5894, 10341, 23980, 31352, 31956, 21426, 19786, 31169, 18822, 869, 8258, 2993, 800, 16804, 27940, 7089, 8949, 22608, 2511, 5630, 23637, 15937, 6605, 24366, 30426, 30047, 3745, 11160, 24376, 11425, 10090, 7932, 32536, 32341, 20795, 27537, 6018, 25136, 31709, 6655, 10371, 2114, 1713, 4375, 15717, 13965, 4539, 19501, 25590, 29233, 28502, 10053, 6002, 4431, 32197, 17089, 6434, 32016, 2164, 32699, 10812, 13627, 8984, 22755, 6730, 5521, 10449, 3876, 6394, 2415, 5741, 30049, 26574, 16019, 2472, 30116, 29633, 14779, 11343, 8731, 31861, 26753, 5096, 24654, 7634, 15138, 8963, 26546, 4960, 12413, 17781, 5113, 3469, 8286, 7277, 32506, 29013, 23, 24726, 29388, 14799, 15961, 28705, 23632, 28647, 7214, 24104, 11656, 1272, 8373, 32430, 15031, 27481, 7253, 25252, 32686, 26725, 20036, 32563, 5056, 32363, 7546, 6164, 24818, 30638, 648, 2506, 1933, 26465, 24703, 20089, 12242, 21704, 23894, 17940, 31729, 12065, 30115, 23679, 24538, 29671, 26356, 625, 25444, 17156, 4104, 6363, 30960, 26256, 4413, 27567, 9726, 1788, 22085, 2181, 4555, 5256, 4188, 12716, 838, 20998, 11915, 17499, 12222, 6733, 8204, 17629, 8881, 16916, 25786, 19661, 20790, 18424, 6485, 10447, 29637, 26711, 21081, 9131, 27017, 2105, 9155, 3749, 32412, 15991, 25438, 3302, 3317, 9345, 26527, 7270, 32725, 27076, 23845, 21202, 3948, 9095, 7396, 16255, 31049, 30941, 9113, 1586, 15546, 14278, 4027, 3903, 4724, 8465, 15986, 13365, 11397, 15868, 17616, 25875, 8344, 20604, 26015, 10879, 16015, 19372, 3635, 24339, 3011, 7326, 14017, 10180, 6855, 19869, 22536, 15458, 3700, 15622, 7274, 5640, 31469, 13914, 24027, 2708, 22427, 8592, 3921, 25506, 23373, 29428, 18043, 29835, 29907, 31498, 15828, 28178, 22218, 10802, 22943, 31944, 5853, 24845, 23275, 5403, 8502, 31488, 22685, 9711, 1900, 7254, 21354, 9942, 9481, 1500, 27665, 15866, 5209, 1377, 6398, 17500, 31314, 1916, 6685, 28393, 3253, 32352, 30735, 2101, 16111, 28815, 22043, 3960, 30141, 32037, 6583, 4285, 15203, 19712, 3981, 19084, 24106, 15807, 25348, 21104, 10584, 30258, 23998, 4372, 32038, 10560, 9087, 2715, 11945, 29592, 2621, 3723, 11465, 24361, 27948, 7033, 31916, 1957, 1496, 29703, 31463, 6858, 4683, 13460, 1714, 12444, 23479, 611, 9924, 31836, 4625, 27027, 1667, 29098, 24092, 14817, 12218, 6720, 4266, 21379, 10469, 31496, 5475, 9637, 24495, 5187, 13517, 26460, 32195, 28418, 17501, 17235, 12625, 196, 9947, 16006, 17388, 20917, 1243, 30234, 9114, 24569, 1571, 8027, 6194, 4466, 29825, 7602, 9175, 15390, 23442, 27203, 24186, 19460, 5128, 4436, 25793, 16491, 24197, 30411, 23485, 7413, 8498, 22223, 2790, 517, 7125, 4221, 27210, 24863, 29758, 1754, 6163, 31134, 25870, 29419, 30298, 2654, 27645, 5181, 8918, 9453, 2656, 20714, 22356, 14019, 23610, 6127, 4730, 17401, 18826, 12892, 31208, 16024, 27229, 10755, 7088, 14619, 20288, 12384, 24799, 21756, 15635, 7661, 2199, 1410, 4209, 29398, 29746, 6914, 30926, 31889, 10302, 16234, 24012, 29435, 10263, 24602, 22092, 28267, 14881, 12948, 12040, 23761, 27557, 4796, 26603, 7310, 30604, 14020, 26718, 30937, 31867, 3001, 22014, 2007, 6673, 32498, 28767, 12068, 18985, 7555, 10764, 32546, 4663, 1118, 7147, 32665, 9360, 31419, 20187, 22942, 14497, 9188, 7416, 7883, 7613, 8933, 5348, 22831, 8550, 7596, 11659, 9609, 25729, 4117, 29612, 963, 29660, 18189, 1225, 6799, 4409, 27769, 32141, 2304, 8107, 22629, 19913, 154, 23151, 14050, 25155, 15249, 2868, 13202, 27145, 9011, 18727, 28582, 5707, 21496, 17942, 14972, 22650, 15008, 5819, 5621, 19483, 727, 30215, 13705, 1736, 18158, 29709, 28194, 2491, 5031, 18752, 18983, 20224, 4986, 28134, 13331, 30698, 7858, 4061, 326, 21596, 12728, 26082, 5172, 27136, 19480, 17153, 27757, 16891, 31715, 29096, 31373, 5726, 23899, 5134, 863, 6130, 5721, 30697, 27979, 15017, 27206, 24781, 4856, 2040, 3162, 2050, 3524, 31328, 5736, 17670, 31122, 24748, 6221, 8822, 32713, 29601, 2807, 25312, 32272, 23540, 1882, 1199, 3106, 2594, 477, 6444, 27684, 28686, 7190, 114, 29518, 26738, 20022, 14605, 21887, 1921, 7663, 30343, 5613, 4920, 3466, 19129, 4145, 25006, 21859, 20864, 20479, 15472, 31445, 10408, 3817, 19663, 22222, 30994, 21183, 32368, 29123, 27829, 22454, 19464, 6847, 5993, 28153, 32159, 30843, 11991, 8292, 28757, 26039, 1030, 18249, 21375, 1425, 29327, 22291, 25443, 12771, 9537, 17140, 6888, 7563, 5363, 28432, 3636, 3461, 2519, 23693, 28015, 26896, 968, 13704, 26991, 2193, 28057, 22927, 45, 5306, 25919, 24461, 524, 1546, 9110, 18796, 19484, 22693, 17194, 10605, 17059, 25853, 30701, 15179, 25727, 10782, 1971, 1556, 24276, 27276, 26042, 24943, 26589, 12543, 24220, 8532, 2379, 18590, 25549, 136, 31759, 13577, 17173, 276, 20978, 7464, 29102, 32508, 14232, 20575, 9898, 23731, 1531, 8386, 16361, 4397, 29012, 25379, 8035, 4121, 9813, 5020, 15533, 5585, 28954, 23619, 22035, 20673, 1718, 6692, 1804, 8094, 3952, 4915, 2331, 4569, 11808, 5824, 9025, 32481, 31691, 32569, 8240, 20145, 17330, 8262, 30646, 26149, 24900, 19387, 14614, 22686, 1705, 30207, 32171, 2832, 21044, 14502, 8371, 9435, 8032, 10038, 23965, 10388, 15344, 10439, 31114, 15901, 3988, 25092, 12140, 18232, 21834, 2770, 9765, 24884, 4165, 9119, 30773, 24574, 25804, 29498, 25820, 19530, 16131, 810, 23605, 19797, 15918, 30946, 6996, 3236, 14833, 20618, 2703, 5062, 31259, 16135, 9690, 3420, 2646, 8860, 5803, 31427, 145, 21370, 21013, 9836, 22110, 10068, 6906,\n12707, 25158, 25737, 16479, 865, 7626, 18126, 26188, 20646, 30461, 6291, 24682, 32387, 29902, 29503, 6951, 2433, 1532, 3515, 7204, 12862, 22636, 18460, 17230, 2002, 4309, 4568, 23554, 18138, 2328, 7001, 26181, 28828, 3406, 17804, 8579, 26579, 5614, 6370, 37, 22219, 28273, 2458, 712, 31269, 6718, 29988, 9289, 26314, 9033, 14672, 26986, 23120, 1964, 20165, 31280, 31320, 26098, 739, 7394, 15837, 21224, 7456, 818, 1797, 6296, 1091, 27064, 9420, 23615, 25, 6714, 31773, 8091, 23878, 11721, 8787, 27811, 27451, 14383, 15721, 16587, 26670, 1374, 889, 9914, 24358, 11855, 177, 3706, 26120, 9643, 22302, 4072, 23363, 15692, 407, 682, 5144, 13748, 21415, 5347, 22538, 5448, 3122, 25647, 26595, 8879, 11858, 18583, 32592, 1665, 24689, 8288, 17925, 16395, 343, 22713, 2875, 27931, 3143, 5354, 672, 18446, 28941, 20879, 4500, 4293, 23512, 22309, 508, 21585, 2289, 28050, 22992, 14127, 4550, 6941, 16502, 28795, 3501, 16157, 22875, 29600, 24470, 1978, 10828, 16288, 8012, 24323, 9452, 17072, 30446, 27234, 20002, 19202, 13048, 13506, 16913, 2887, 27821, 17784, 8064, 25349, 23806, 924, 4012, 25189, 25876, 21101, 18769, 20809, 7588, 19774, 9315, 31333, 2838, 23568, 28468, 8774, 27314, 32417, 3864, 13720, 17809, 7677, 17905, 23875, 8418, 10900, 9285, 21878, 26436, 23528, 18955, 15739, 30377, 21019, 5245, 5393, 6257, 10792, 7726, 4237, 12359, 31871, 554, 26267, 2958, 8018, 28208, 2385, 8889, 30305, 8846, 4783, 15794, 8463, 30009, 23438, 1961, 16397, 14361, 7485, 13095, 599, 23284, 23618, 25047, 6624, 16056, 20892, 12250, 28897, 2420, 9431, 22666, 6390, 5034, 22882, 6254, 27957, 947, 27021, 25954, 908, 16834, 5837, 9787, 11048, 23331, 22796, 31043, 7881, 4981, 23926, 26940, 7067, 29310, 3696, 14229, 23319, 1529, 25662, 6703, 2460, 14731, 25248, 2158, 30764, 28805, 29805, 6013, 27042, 1120, 8073, 19220, 29131, 3555, 25338, 24982, 16000, 28668, 16411, 17008, 16917, 20202, 3782, 26820, 3295, 6629, 10699, 22952, 18596, 16884, 9738, 2392, 26130, 16603, 7257, 17403, 32355, 30280, 7968, 1042, 8212, 19245, 10138, 5897, 27306, 10860, 21989, 13770, 14749, 9297, 22559, 29623, 3252, 20321, 13740, 19713, 4523, 26296, 26109, 5487, 4240, 2664, 3552, 20543, 29173, 5580, 21407, 23054, 5370, 30889, 28872, 31570, 28105, 6760, 6598, 15772, 19331, 28117, 6010, 30366, 12041, 24386, 1358, 22429, 13082, 27773, 8385, 10463, 6536, 10331, 9764, 24724, 30637, 8605, 8108, 22583, 18847, 31737, 21452, 13696, 28344, 1233, 6377, 10456, 4271, 28465, 29272, 24782, 84, 31999, 22954, 56, 31872, 3824, 12582, 22351, 1616, 4107, 29743, 25766, 7909, 22843, 22785, 4530, 10072, 7074, 30150, 13281, 32697, 22423, 519, 8740, 7107, 7076, 22432, 2393, 10971, 21587, 11743, 2239, 3802, 7861, 23449, 31342, 31791, 7977, 11457, 27740, 19293, 9497, 19628, 12394, 19291, 23664, 5107, 24445, 14332, 509, 1082, 29183, 4227, 2998, 24751, 19691, 9183, 32005, 20270, 10431, 9404, 17318, 20114, 9416, 3178, 25285, 15152, 25771, 12915, 14337, 12788, 5066, 15177, 29332, 19968, 20584, 27418, 9246, 16020, 30715, 8162, 21745, 7567, 10164, 10256, 29843, 10494, 12154, 16094, 1342, 32529, 28484, 10337, 20339, 29239, 22073, 24583, 10219, 25639, 23309, 29079, 10446, 8442, 1341, 797, 141, 7925, 5687, 199, 26743, 1506, 1294, 8844, 15690, 32747, 3458, 26371, 21288, 2831, 23612, 5064, 2515, 9067, 4793, 3826, 2852, 25533, 2044, 20734, 16620, 32365, 28545, 28855, 19959, 2118, 30445, 17376, 26935, 10453, 4914, 31220, 20826, 15670, 16712, 20880, 12526, 6845, 10460, 22818, 28659, 9164, 26318, 25222, 27992, 30745, 30979, 26590, 29356, 1612, 25133, 22691, 11694, 8130, 22609, 7614, 4503, 17139, 7453, 4762, 30430, 4764, 23634, 1740, 443, 28717, 30208, 11114, 18887, 31857, 22272, 30302, 18464, 9565, 8819, 19326, 25301, 26602, 31684, 15970, 21455, 26375, 17908, 14898, 996, 8518, 27634, 558, 29439, 1068, 9479, 8743, 15399, 6727, 4943, 15651, 26298, 31732, 31156, 22806, 17852, 21660, 5780, 3243, 27511, 25478, 7836, 30291, 19380, 3528, 24416, 25110, 9602, 7606, 27424, 7072, 28443, 32314, 6108, 30709, 6564, 21826, 28444, 7176, 6777, 3763, 2250, 26178, 2160, 9549, 15060, 12104, 1716, 14597, 13188, 7716, 3741, 23046, 6929, 4930, 24301, 3787, 26230, 4106, 27721, 1562, 8528, 20220, 21891, 15323, 28460, 19778, 21089, 28922, 25780, 6904, 27951, 30362, 16703, 11962, 26878, 5596, 6770, 8541, 4761, 8425, 17184, 1431, 27059, 14524, 10018, 12093, 8374, 30680, 7922, 3897, 26464, 23344, 29692, 5753, 12372, 17688, 27230, 13557, 4980, 13491, 4896, 29436, 7739, 3260, 31026, 9610, 20411, 6275, 7026, 29172, 4946, 11921, 21680, 14636, 3036, 17745, 11925, 7575, 28216, 9396, 9599, 29182, 21929, 5851, 8687, 10727, 3259, 28952, 28850, 19150, 4517, 25262, 9667, 1491, 18811, 23601, 30864, 25798, 10742, 19553, 26995, 10840, 32743, 6213, 4028, 2604, 26284, 28415, 27525, 12940, 10197, 28696, 27628, 28077, 28915, 25374, 10397, 28629, 3000, 24295, 7443, 4438, 4315, 10120, 24330, 16897, 9605, 6946, 23616, 5570, 2337, 31382, 9097, 5905, 20192, 10317, 13903, 11230, 2978, 3066, 6719, 13297, 27764, 11528, 10274, 26473, 30724, 29100, 26977, 24205, 27493, 19550, 18390, 16148, 32505, 8254, 14901, 20318, 3905, 6768, 10275, 323, 21155, 23545, 25503, 6335, 25651, 15600, 32687, 29664, 17801, 29109, 15815, 29737, 10531, 1611, 24174, 31881, 6134, 29059, 13674, 16838, 8745, 2969, 7880, 29188, 15315, 13312, 31465, 27131, 22737, 2608, 29604, 2069, 20452, 24658, 26084, 9859, 859, 27110, 24525, 29552, 28490, 10963, 1555, 2081, 8994, 7071, 25707, 2188, 9012, 7725, 28595, 13657, 11718, 31635, 19717, 30160, 14072, 13645, 644, 9671, 13168, 7081, 1171, 9606, 11852, 5386, 24447, 11240, 531, 30239, 12879, 22973, 7659, 26646, 28449, 22407, 11021, 27883, 9835, 20116, 25025, 9840, 13925, 30547, 17120, 26834, 32658, 28467, 9969, 25500, 23943, 13538, 1703, 5156, 7248, 27271, 23368, 16432, 27436, 13047, 4044, 7247, 31313, 30589, 3511, 26327, 12039, 14293, 7196, 20513, 23317, 11121, 22916, 20896, 18328, 1540, 2739, 8415, 1399, 31906, 6184, 6916, 8484, 8525, 6236, 19689, 29179, 27761, 14385, 944, 30265, 14775, 10161, 24646, 3971, 14466, 5235, 26191, 29755, 2443, 26537, 26981, 776, 7339, 1709, 8057, 4302, 2323, 32501, 30762, 27853, 1985, 9780, 7692, 8189, 6979, 28938, 28069, 25900, 4245, 12926, 7821, 21591, 24063, 23984, 24442, 6744, 1962, 5512, 30163, 4772, 19355, 1080, 24268, 19753, 24273, 28849, 28951, 29533, 26971, 30237, 5516, 26895, 20157, 9196, 19418, 22109, 32042, 13318, 18545, 31262, 29369, 11154, 8763, 18254, 31363, 24064, 26014, 7561, 2268, 11358, 23307, 27164, 31799, 23118, 25173, 30634, 13906, 1176, 6385, 26403, 30179, 8439, 12337, 9721, 32148, 19274, 29960, 5036, 28220, 22857, 24047, 20959, 10450, 17621, 18978, 14956, 1134, 17274, 9747, 26599, 14400, 861, 13463, 17255, 3186, 27965, 18968, 10301, 22232, 32759, 4310, 21270, 6274, 22484, 19292, 8367, 28001, 22786, 12102, 11499, 10417, 16109, 26639, 25046, 20638, 21733, 10360, 7770, 1603, 20255, 26469, 321, 32371, 10477, 26687, 9563, 8677, 16031, 24606, 10993, 29782, 27976, 17392, 24674, 17462, 27828, 17415, 3848, 12535, 5814, 22705, 13707, 27561, 24215, 24534, 7496, 23509, 20873, 7830, 22898, 18929, 30817, 13947, 6361, 7360, 31835, 31518, 28398, 15, 9903, 25883, 5731, 4498, 22168, 24927, 7179, 9632, 22065, 30050, 16089, 19980, 18481, 27143, 18880, 32425, 22156, 18261, 6696, 12798, 28045, 32639, 3908, 32072, 3950, 5770, 7404, 25602, 25204, 15450, 21800, 16736, 3536, 8524, 3285, 28272, 16921, 16628, 31840, 10691, 26735, 29379, 5050, 26080, 22601, 19881, 13619, 24627, 12656, 5631, 31795, 22489, 13273, 22422, 26184, 25310, 4069, 1168, 20325, 23100,\n2326, 25400, 30577, 7489, 22938, 25361, 31356, 18421, 14039, 8943, 1241, 25751, 10215, 2532, 3298, 27875, 32704, 31967, 18316, 10122, 15925, 16179, 7810, 4791, 3871, 14904, 27321, 100, 29099, 30264, 25226, 10817, 7417, 16391, 19018, 32093, 31891, 3909, 667, 24002, 12032, 17108, 8641, 8538, 32100, 12113, 15693, 25806, 9687, 9062, 24373, 22983, 2217, 20536, 21633, 6523, 22568, 13073, 11552, 29819, 27641, 11928, 24071, 2619, 20343, 8810, 18710, 15544, 6210, 22019, 29647, 8337, 28880, 17034, 3744, 23172, 29457, 13235, 1104, 20032, 15816, 21697, 13197, 2146, 32461, 5805, 2478, 1817, 9547, 19990, 23494, 14124, 4570, 7079, 9016, 28170, 1879, 6535, 5996, 26146, 2960, 28080, 8667, 1437, 15155, 31433, 5757, 14970, 13663, 26638, 370, 14316, 10094, 25067, 16518, 8121, 17664, 17112, 7524, 18934, 9806, 27717, 7209, 20634, 6036, 23353, 10580, 31332, 2526, 21404, 4850, 10944, 22238, 2716, 14061, 19422, 29490, 9460, 703, 13039, 28278, 5852, 4751, 4432, 7985, 17684, 29026, 30739, 9502, 31940, 9564, 27023, 13440, 11711, 4537, 10778, 14781, 20334, 5051, 10696, 2710, 11196, 25021, 6349, 25261, 11350, 6269, 31720, 32101, 3621, 11088, 7675, 29075, 1477, 26446, 32102, 17786, 25885, 27565, 17185, 24020, 5333, 30641, 13394, 11506, 9716, 20091, 9651, 19287, 16242, 16182, 18971, 7241, 16095, 28559, 17301, 6080, 22921, 25241, 27303, 22359, 5830, 30133, 6051, 25613, 21978, 13521, 30783, 7855, 3023, 27179, 1578, 25106, 886, 30605, 8033, 25176, 10100, 22833, 6509, 27390, 31173, 9678, 12953, 12059, 5090, 22277, 22391, 16460, 23315, 8650, 12586, 7807, 32268, 26593, 12273, 13964, 2825, 13270, 21513, 4922, 6684, 8485, 22731, 6311, 10052, 7268, 32315, 9004, 2816, 11200, 20304, 30585, 11204, 32489, 9001, 9143, 24040, 8734, 20344, 26747, 8751, 17191, 19340, 19957, 2279, 10228, 6136, 10796, 706, 355, 12955, 7314, 11424, 20823, 5018, 11687, 24825, 7182, 11951, 19922, 18804, 12190, 26118, 7691, 5798, 24765, 28332, 28887, 1914, 22220, 21917, 20593, 14059, 17657, 8178, 19479, 6115, 28539, 16540, 26987, 23739, 19827, 18566, 4383, 20931, 29341, 8517, 28283, 8410, 1684, 10158, 7504, 31958, 8969, 6895, 31318, 29640, 21714, 32257, 24553, 7522, 8685, 1004, 11541, 1577, 3762, 6253, 4501, 17903, 18803, 7434, 24921, 22709, 6746, 1702, 1255, 25971, 10245, 3516, 31376, 4616, 16227, 28572, 3951, 24302, 10073, 11842, 4703, 16953, 30410, 7160, 9170, 1065, 5522, 3729, 16206, 31212, 25031, 3940, 17915, 9525, 9869, 31350, 6969, 17484, 10145, 18326, 19158, 5311, 21477, 26833, 3321, 3681, 14733, 2350, 26092, 12972, 26325, 3735, 5561, 5756, 5004, 28803, 17570, 27729, 29154, 8549, 12806, 11290, 9929, 10495, 30862, 4925, 22088, 3017, 15804, 14644, 7601, 22341, 4642, 18198, 30488, 24603, 26096, 28772, 1745, 25628, 13589, 29846, 29543, 5189, 8544, 29366, 1175, 27866, 14979, 2855, 9042, 24996, 24858, 643, 31542, 24397, 21373, 21366, 21986, 3263, 7853, 12315, 23078, 19071, 6963, 26778, 26345, 22286, 25359, 17605, 18065, 25655, 12832, 6522, 19738, 18888, 20282, 8476, 13496, 17867, 14302, 17331, 17470, 14320, 6288, 12412, 27162, 6530, 29330, 16902, 23737, 7878, 23565, 31912, 11451, 10297, 30002, 10078, 11274, 31108, 9784, 22305, 29776, 9472, 529, 7568, 12248, 23789, 27955, 27349, 32111, 32029, 28997, 26006, 22838, 19894, 5682, 6815, 2660, 25658, 2985, 26915, 26879, 19806, 29450, 10507, 8197, 28142, 5685, 3808, 10889, 13381, 2156, 20753, 11479, 6418, 5713, 23950, 30396, 26673, 11564, 21180, 14294, 31992, 24003, 16744, 8511, 26634, 2034, 9953, 24392, 26648, 20440, 4234, 11251, 22127, 29042, 8098, 12281, 32117, 8468, 30768, 24107, 27863, 2973, 29572, 30852, 21612, 17481, 28268, 21931, 30837, 17682, 28759, 32611, 795, 29155, 15393, 20227, 3984, 19640, 1618, 7458, 2464, 11762, 32750, 17491, 29548, 7644, 345, 28453, 26714, 1353, 27439, 24127, 464, 10994, 26221, 21940, 8181, 17760, 23777, 11418, 27453, 29322, 14959, 13862, 17818, 30517, 4626, 7018, 10604, 29242, 8690, 30485, 22592, 24513, 26342, 14635, 7895, 6475, 10438, 30636, 30306, 18763, 3724, 18747, 12865, 17088, 18304, 3004, 10240, 30522, 17051, 2603, 9737, 6212, 32669, 27783, 8708, 30185, 23180, 5462, 3472, 11611, 374, 1806, 2518, 32215, 31477, 5505, 10177, 9604, 29306, 22213, 5331, 23004, 3470, 22021, 589, 25892, 5214, 9426, 30597, 6794, 15616, 9306, 17904, 4959, 10527, 2281, 9056, 938, 31268, 31985, 22457, 3267, 13824, 25378, 1332, 22138, 27060, 22473, 11627, 19707, 18445, 29509, 21400, 13911, 17740, 27135, 23293, 27175, 7526, 29587, 7917, 1031, 22246, 4643, 28348, 30033, 25969, 29245, 20150, 2228, 19560, 32734, 32623, 8913, 4824, 641, 9438, 6226, 22933, 11463, 6016, 735, 29049, 11101, 4513, 15408, 30845, 10205, 4435, 11735, 27253, 6152, 24531, 24716, 762, 13213, 17970, 6689, 4347, 18781, 31008, 14455, 23093, 30472, 24611, 622, 25714, 25481, 24143, 4923, 6083, 23783, 22350, 28914, 10608, 7163, 686, 2631, 21818, 15429, 11741, 29415, 7145, 21453, 24135, 2484, 28943, 22476, 27434, 15768, 1258, 9247, 3153, 18779, 5835, 24391, 4127, 13211, 9590, 25930, 5879, 2176, 21651, 27749, 26244, 25735, 20869, 7802, 18313, 15506, 17098, 7773, 27378, 19905, 27209, 10751, 872, 4909, 24758, 31200, 7418, 31638, 24178, 20676, 14183, 22939, 20833, 3781, 31952, 26562, 22865, 16934, 18422, 27448, 9450, 26916, 12336, 29540, 17526, 17346, 28933, 24680, 28238, 20251, 3147, 27487, 4295, 16378, 25653, 17028, 12807, 24824, 2659, 29347, 31191, 5014, 30763, 20852, 7455, 25144, 24850, 26621, 32353, 20642, 11577, 9361, 5917, 23163, 13685, 24576, 20910, 24504, 23108, 2329, 18812, 551, 1687, 31789, 3544, 15744, 4688, 20275, 31641, 24914, 29113, 11062, 25014, 14430, 8808, 16093, 29791, 29994, 17669, 5959, 6773, 15420, 18785, 11575, 26282, 11719, 8696, 15628, 22102, 2777, 400, 2628, 8727, 7803, 3567, 5979, 8898, 16057, 30887, 21822, 21613, 920, 22137, 18221, 1781, 6400, 12804, 17493, 23963, 7748, 24735, 7558, 27462, 17181, 501, 5591, 24880, 1006, 5568, 6392, 4150, 5737, 12196, 10098, 4100, 313, 7509, 14871, 21091, 21676, 8666, 31295, 5639, 32757, 3865, 13321, 4659, 32574, 21032, 23908, 282, 30142, 32240, 23123, 16608, 5875, 21008, 12763, 8190, 10001, 27629, 30957, 23075, 11187, 23436, 2912, 20406, 29867, 28846, 28589, 27693, 24015, 14639, 5412, 17564, 16174, 11060, 10160, 3665, 26000, 4091, 17705, 22779, 1939, 2316, 30730, 9708, 7929, 4650, 14506, 23276, 18904, 27046, 20161, 32017, 4060, 6664, 26025, 24876, 10799, 26515, 17999, 22764, 7641, 23695, 10623, 7983, 448, 10992, 11209, 31458, 29235, 24311, 16724, 25083, 30661, 32190, 21556, 17794, 5310, 2387, 17836, 22717, 28597, 26137, 3131, 21344, 20368, 4279, 21508, 20611, 19427, 5237, 5530, 14991, 26051, 3235, 1857, 20056, 28899, 774, 29417, 12860, 5964, 32754, 26368, 3597, 1327, 5440, 22392, 28419, 5762, 2848, 2098, 21220, 7387, 2613, 25879, 29237, 28328, 7956, 22944, 6375, 10632, 21310, 23870, 5619, 7609, 13266, 22400, 27859, 23404, 7756, 31456, 2844, 7382, 17251, 4407, 9541, 30776, 24126, 23398, 12956, 5659, 24909, 1010, 29750, 24285, 3804, 21536, 317, 4029, 23707, 20599, 18046, 4902, 2776, 811, 13536, 13426, 10096, 21957, 11103, 13288, 25231, 3204, 9493, 26967, 6789, 3550, 11532, 13643, 9084, 18385, 17161, 14828, 10295, 31885, 23064, 673, 32403, 11169, 15154, 6889, 23804, 26961, 21770, 19499, 26486, 12108, 9376, 29627, 3775, 2762, 15634, 3886, 24709, 25592, 596, 504, 28373, 2590, 30965, 6856, 14705, 3238, 30128, 7194, 8825, 23411, 30542, 10129, 24303, 11550, 8540, 1359, 24213, 23325, 27947, 15480, 880, 23816, 1657, 10330, 25033, 27161, 30703, 32597, 16765, 25552, 27959, 6112, 21441, 15357, 13760, 23215, 26988, 27964, 19469,\n6864, 5624, 11092, 21383, 23049, 17792, 331, 8985, 21783, 10250, 167, 7625, 4004, 27942, 6695, 26559, 4577, 24228, 21124, 19906, 2976, 19605, 18359, 31510, 29395, 32420, 20103, 21133, 28062, 12877, 17210, 12084, 24677, 11106, 19624, 12780, 23364, 4267, 11280, 25621, 10674, 32019, 22155, 27752, 9556, 22547, 7942, 2456, 13484, 902, 25257, 32090, 23748, 23836, 5884, 8154, 4134, 24932, 16354, 11911, 4542, 5956, 26263, 3881, 14958, 21201, 1304, 6145, 14797, 11861, 9384, 4494, 15825, 26289, 29717, 5441, 4581, 16750, 15872, 549, 6368, 25143, 24449, 19805, 21009, 20729, 28091, 30385, 4116, 23921, 21642, 11816, 25593, 2747, 12903, 26204, 31679, 1581, 25548, 6854, 28657, 19495, 6197, 505, 23698, 27057, 32720, 11286, 10982, 7393, 30573, 2389, 2728, 15743, 18362, 28447, 12004, 26320, 28430, 19586, 13279, 6809, 7564, 3490, 10093, 3664, 26773, 10114, 2798, 28477, 2216, 6800, 26360, 22271, 17938, 1734, 431, 11588, 8954, 24641, 7947, 32531, 480, 9234, 31845, 14927, 32683, 10787, 2687, 25372, 3756, 19744, 30019, 22542, 10730, 8452, 9727, 10673, 363, 2218, 14261, 8368, 20661, 20820, 7495, 10948, 16935, 5895, 1230, 10810, 3428, 20478, 25397, 12089, 25018, 19822, 23828, 16313, 5701, 30657, 20546, 30779, 32451, 22157, 3816, 29373, 1432, 24582, 29542, 10214, 6088, 24692, 11265, 19449, 4123, 7463, 10717, 6346, 30758, 32265, 28131, 1167, 3619, 28575, 20971, 6662, 15626, 31085, 31071, 9538, 18469, 26304, 14188, 10410, 12564, 19032, 888, 31466, 13600, 4689, 7471, 29721, 25863, 28558, 22977, 26799, 24607, 10711, 5877, 24163, 10394, 5702, 7480, 14714, 9742, 21541, 31955, 8902, 24412, 27345, 6303, 10188, 3494, 515, 1896, 25152, 27107, 31511, 25586, 32145, 24242, 6096, 6278, 21515, 21741, 7047, 3982, 27146, 23781, 556, 32516, 30060, 8244, 26911, 7618, 3587, 27375, 20429, 12005, 28640, 29593, 9485, 4251, 9294, 13347, 22541, 13399, 3686, 24679, 28125, 19414, 9395, 11228, 20269, 26748, 20660, 7166, 4348, 21594, 29943, 32422, 2959, 1638, 16573, 15053, 5203, 21914, 20999, 7198, 18726, 11362, 23181, 21055, 27119, 9392, 29132, 5392, 19636, 28222, 15418, 25837, 22508, 2291, 9569, 29187, 29159, 27855, 31526, 25099, 7974, 31407, 32424, 20294, 30476, 19622, 26135, 1599, 4450, 27357, 26852, 28256, 6408, 26516, 26696, 13876, 26050, 6650, 8451, 27898, 12211, 10299, 23059, 17646, 12436, 30129, 17, 11227, 12492, 24438, 12705, 28129, 10783, 29571, 25630, 19563, 28895, 1404, 6298, 25562, 23660, 12483, 23235, 19999, 10613, 31086, 2292, 27118, 2234, 3606, 9286, 11689, 28743, 27407, 26939, 30171, 20522, 21010, 10731, 14777, 22101, 8149, 25823, 2772, 22752, 12592, 23339, 10233, 9014, 5680, 13404, 17662, 3718, 30642, 12551, 21446, 7600, 15371, 13237, 24939, 32429, 12588, 20985, 115, 7660, 22408, 9710, 995, 7705, 8295, 12056, 7904, 13811, 22346, 20806, 19697, 25210, 30565, 6060, 17162, 16451, 4810, 26552, 26400, 22853, 30644, 4048, 22801, 22297, 17710, 2413, 25842, 27623, 17742, 24699, 26665, 24549, 11177, 10099, 18380, 8207, 5672, 13311, 21246, 4807, 28086, 31127, 25669, 9142, 5523, 14582, 9478, 3299, 19496, 12765, 30246, 21584, 120, 15879, 20816, 23299, 24158, 10005, 5557, 26246, 24838, 28031, 2430, 587, 21255, 31225, 28969, 10187, 2524, 23321, 8359, 20026, 29077, 7946, 2032, 16567, 779, 9702, 14677, 7799, 18674, 23057, 4199, 27766, 29403, 31649, 28158, 31571, 3398, 11844, 5785, 10049, 31672, 4973, 68, 28930, 11723, 22522, 21824, 29645, 18093, 11644, 23457, 2837, 22645, 5587, 11041, 27831, 3977, 9217, 28305, 15682, 31787, 7930, 17077, 32568, 24398, 9216, 23282, 28618, 12797, 8946, 26700, 13529, 8815, 14450, 2099, 21942, 29246, 20209, 27569, 6449, 29034, 24902, 23048, 28626, 5740, 17164, 30344, 22200, 30538, 24809, 6797, 31563, 15207, 32052, 10779, 24878, 24771, 12402, 9826, 20097, 359, 4023, 787, 31147, 7211, 6919, 27727, 12749, 14758, 30795, 21384, 22812, 5860, 21438, 12320, 20761, 17751, 12152, 19826, 29957, 8082, 8325, 12869, 10704, 28017, 22335, 11905, 9003, 10115, 12451, 25848, 15285, 22257, 4672, 24869, 3973, 32628, 22460, 11902, 4425, 7315, 7645, 19428, 32026, 4955, 27961, 11653, 10210, 30596, 24920, 1845, 1266, 6331, 18605, 29824, 6607, 8758, 7777, 3740, 10835, 21848, 32471, 1798, 29736, 31522, 1544, 6942, 20733, 31337, 15217, 27519, 21667, 24270, 3254, 21558, 29095, 25051, 7410, 32259, 27751, 11198, 10478, 13417, 7287, 7908, 27677, 26367, 32728, 32049, 26295, 5338, 6987, 4194, 1902, 18034, 25227, 29399, 23081, 27935, 24501, 8155, 2439, 31564, 27921, 2735, 19517, 26862, 3589, 9957, 11985, 24573, 25504, 21046, 2624, 23329, 24369, 9172, 24789, 2752, 9854, 23879, 3508, 5315, 24123, 1101, 20739, 30010, 31756, 13138, 10614, 19240, 7140, 26936, 14517, 18711, 31764, 8274, 28563, 30148, 19859, 27277, 24790, 2074, 26065, 7589, 1261, 25355, 14395, 17314, 560, 20010, 10752, 2391, 2627, 8039, 30857, 26669, 9587, 21869, 862, 25303, 15352, 17019, 741, 24822, 5052, 27925, 19838, 2765, 10269, 13057, 20148, 22339, 13094, 32264, 18433, 25920, 19374, 30606, 5898, 17806, 29038, 12349, 18452, 32299, 23824, 21690, 1172, 15752, 24316, 23039, 20108, 27823, 20839, 8944, 23997, 107, 19579, 8192, 1937, 32001, 32550, 4184, 19421, 18425, 30677, 22154, 8077, 1112, 29809, 27658, 4668, 6952, 7896, 4648, 8054, 24059, 7202, 24451, 25039, 26442, 26468, 11084, 26196, 24564, 3146, 20107, 30027, 32115, 12186, 20709, 166, 20969, 4735, 30549, 21123, 7762, 22234, 25878, 222, 12979, 5801, 10770, 19848, 11363, 10226, 8494, 29166, 2380, 12789, 21283, 410, 6165, 27652, 15962, 13158, 29302, 6314, 30688, 32441, 13176, 8961, 22198, 6043, 29982, 2504, 21656, 30663, 2553, 30283, 17829, 5213, 9134, 22656, 7352, 14985, 30197, 15992, 26970, 31298, 29247, 4918, 627, 9017, 20518, 15609, 30112, 25059, 5549, 12813, 23906, 5091, 13555, 10401, 15939, 23644, 14987, 4399, 10719, 12519, 21285, 22771, 11059, 27045, 616, 22682, 29919, 18687, 11608, 12883, 25974, 6982, 11220, 8520, 28225, 21635, 8839, 3234, 20835, 5327, 17479, 8475, 19519, 22742, 19288, 31702, 24256, 25745, 27245, 20242, 4790, 31506, 21678, 172, 3713, 25120, 21742, 13975, 19729, 13715, 3669, 7698, 11938, 6580, 3819, 19411, 8398, 14870, 5243, 9562, 18197, 1893, 13342, 31388, 31171, 15654, 13112, 9785, 2075, 29926, 18468, 7903, 4439, 11494, 15497, 10525, 24669, 20622, 6717, 27221, 11406, 12172, 3674, 7910, 25671, 26334, 660, 21692, 12823, 22956, 5336, 21226, 23579, 25718, 13530, 25708, 1100, 9700, 25465, 2386, 21451, 10181, 2783, 14750, 1856, 10939, 26999, 5129, 29251, 30798, 9867, 11695, 30643, 11866, 8099, 22430, 22738, 31399, 12651, 20991, 23066, 6785, 14951, 27647, 9777, 22947, 22714, 7395, 26030, 22434, 25073, 9539, 10959, 21140, 19934, 10325, 10878, 27654, 4814, 31338, 25961, 6567, 28796, 17258, 28058, 8471, 3069, 30940, 9704, 29376, 11821, 10709, 30383, 25958, 18574, 11046, 25165, 10950, 15268, 30496, 20768, 10714, 12613, 12700, 30153, 28039, 6899, 22618, 2296, 4473, 32285, 7856, 16709, 6555, 14452, 6893, 27231, 21779, 25354, 5826, 27050, 28175, 17283, 21329, 265, 14894, 10853, 21454, 28004, 27000, 10612, 4470, 14222, 975, 24954, 24772, 416, 8119, 23264, 21530, 21715, 12144, 32337, 28794, 23500, 4304, 30561, 1819, 13287, 26640, 23862, 6935, 10251, 23798, 29408, 28185, 3408, 22774, 23531, 18782, 6694, 8038, 20023, 19164, 32035, 14190, 8914, 575, 12951, 3613, 5467, 8512, 6109, 13348, 12850, 1504, 3599, 12596, 11043, 764, 25596, 20908, 21063, 1232, 20458, 15644, 11061, 13294, 8298, 2025, 14789, 22689, 11955, 2986, 22189, 27188, 16874, 8702, 1785, 26083, 30206, 8198, 8294, 9292, 11998, 1596, 2033, 12232, 31036, 12077, 16233, 23018, 20497, 2374, 1746, 31467,\n12615, 11580, 15754, 5611, 20007, 21242, 11885, 25683, 4140, 8906, 217, 1451, 4989, 13513, 26877, 18868, 24601, 28095, 15723, 8571, 20499, 14114, 271, 186, 22029, 18307, 32409, 20467, 16872, 19619, 24950, 25827, 29106, 26406, 9386, 6285, 29748, 20155, 12744, 20365, 9979, 11641, 13104, 6255, 5444, 10763, 24288, 9735, 31750, 22023, 22398, 11734, 6294, 31106, 6223, 4606, 28012, 2813, 11802, 9255, 11680, 22022, 23097, 7197, 19065, 30719, 8409, 16348, 1904, 18544, 25582, 14585, 16262, 6961, 22293, 21173, 10462, 12609, 10109, 25138, 28403, 15521, 1589, 9819, 25838, 21812, 9020, 8892, 6348, 21381, 30903, 21819, 21094, 11974, 11002, 24545, 8287, 15786, 5218, 992, 7207, 6653, 31596, 11432, 25040, 17799, 18204, 24841, 24907, 11401, 4519, 25865, 3899, 24172, 11396, 7709, 31392, 32249, 30607, 2013, 6679, 12227, 16049, 32545, 24145, 1874, 10583, 7014, 8097, 30005, 1388, 30869, 31017, 6143, 13575, 30506, 7029, 11995, 13115, 612, 14290, 20080, 4465, 2089, 4804, 23190, 1464, 15044, 27648, 19820, 13148, 19705, 7233, 8572, 31876, 13752, 9311, 22743, 20303, 7105, 27777, 20250, 32176, 21177, 8854, 31805, 16564, 23662, 30004, 14571, 14802, 29370, 11175, 20506, 10079, 15806, 18172, 8438, 31309, 31245, 31721, 9150, 13920, 23696, 10710, 5111, 29378, 9312, 7734, 23711, 12470, 31580, 12715, 13482, 12225, 31028, 14365, 9280, 5975, 20752, 3272, 3702, 12308, 19893, 31385, 4613, 14137, 11770, 9956, 9554, 9918, 18799, 10399, 9073, 10736, 25380, 15226, 9954, 18079, 160, 14040, 26647, 8766, 13036, 1133, 23246, 19528, 26448, 32599, 11917, 10781, 9585, 7820, 3748, 17310, 11119, 27667, 12868, 27745, 25202, 15130, 15218, 29433, 22700, 10977, 21171, 26575, 22382, 9241, 26954, 12373, 14482, 11207, 31121, 19242, 6476, 11033, 16721, 4080, 21191, 29980, 5247, 9434, 8208, 22660, 32488, 32680, 23311, 8050, 28511, 13570, 12020, 12751, 4342, 13218, 19776, 15580, 6154, 19284, 4476, 17560, 1277, 23291, 9745, 5101, 17446, 19609, 28437, 31902, 11990, 15201, 25555, 3284, 19027, 8488, 27646, 13861, 8655, 4544, 9817, 13109, 30402, 23302, 5617, 31800, 21820, 32277, 24926, 2778, 14211, 3385, 5490, 28141, 22160, 5727, 7894, 10801, 10435, 4696, 22635, 6277, 27328, 13805, 23197, 6873, 24291, 12847, 30548, 27564, 5595, 12822, 5748, 31812, 274, 18101, 8903, 25688, 14897, 24585, 31997, 6853, 11093, 12587, 9283, 12539, 15532, 27755, 3467, 928, 18049, 26421, 26354, 29119, 8717, 26771, 12143, 28417, 24747, 29783, 7840, 28485, 11804, 19361, 18841, 32760, 9427, 9195, 30151, 31378, 3371, 16123, 12285, 31546, 5673, 1553, 4215, 12653, 12496, 29406, 15711, 179, 3329, 1037, 12718, 980, 30766, 9976, 7439, 18371, 29424, 13062, 19936, 2552, 5330, 24098, 31272, 19059, 31559, 19873, 22349, 1483, 20471, 28109, 21012, 30326, 28548, 32234, 564, 6114, 23443, 19650, 30089, 8487, 1305, 9181, 28407, 20384, 10314, 11975, 12364, 21031, 12255, 31695, 10125, 8307, 17243, 26086, 12106, 1998, 13067, 10829, 23423, 2197, 20635, 30073, 24786, 20402, 29772, 26275, 17060, 5501, 29935, 11746, 13565, 3347, 9271, 29274, 17837, 3600, 12103, 20287, 959, 28660, 15659, 19336, 23249, 22598, 21798, 24923, 9849, 6492, 12199, 22231, 27029, 1629, 9174, 22996, 13098, 27660, 1300, 21751, 11278, 15307, 2149, 28227, 4559, 13056, 21896, 7218, 27971, 18209, 8332, 9792, 8883, 12560, 10022, 11079, 20960, 31904, 27207, 6828, 4204, 1784, 8446, 2763, 26795, 18475, 23690, 969, 21652, 9381, 31364, 1624, 28949, 9938, 4937, 1761, 13409, 4864, 478, 19596, 12958, 25675, 1508, 16186, 12997, 27562, 29516, 11017, 23620, 8500, 28483, 7934, 20719, 16150, 9638, 8141, 7967, 19800, 29538, 1762, 30243, 7232, 28140, 15999, 16370, 3322, 23236, 19890, 27905, 11639, 4228, 12929, 25075, 7040, 1302, 23697, 1020, 16851, 10728, 13723, 25453, 17555, 10328, 16039, 16676, 29144, 31847, 14858, 10207, 19089, 17766, 25730, 27496, 14370, 17215, 28672, 3963, 2219, 12981, 257, 10069, 5200, 22968, 5834, 3015, 26055, 31475, 12528, 23689, 19961, 29742, 18199, 7529, 19536, 27592, 23571, 9184, 19386, 9560, 9408, 2975, 26938, 12404, 11742, 21076, 28228, 29502, 1311, 2366, 31082, 24211, 2744, 6601, 22949, 10236, 12514, 535, 24331, 3918, 20684, 9509, 2897, 19261, 29410, 19892, 13425, 8321, 108, 7628, 13198, 18883, 4819, 1839, 5270, 29380, 5776, 32496, 21786, 12579, 25507, 21442, 7752, 19547, 26189, 21941, 7342, 22753, 8296, 18514, 8067, 2780, 24868, 20555, 27678, 12447, 23581, 18744, 17856, 31662, 30962, 24035, 25258, 9339, 17840, 2424, 21629, 11036, 22256, 3209, 21720, 18821, 28906, 14036, 6246, 13528, 27327, 9005, 5645, 14053, 28603, 29803, 19322, 334, 20046, 18701, 32552, 9582, 21796, 9839, 29052, 29411, 20495, 19309, 6405, 26016, 31718, 14249, 10874, 9994, 12748, 11178, 9703, 30672, 11901, 7671, 25346, 22240, 17338, 9575, 12271, 2999, 23416, 8478, 3384, 30217, 31739, 5205, 23173, 23347, 8089, 12029, 26613, 4584, 1513, 30859, 11981, 13350, 6433, 23543, 7681, 11636, 7061, 23510, 25383, 3303, 2485, 595, 10848, 25913, 5734, 7963, 29137, 26846, 27542, 18742, 15426, 29794, 6769, 24630, 18535, 31228, 8422, 10458, 12298, 3615, 1823, 30439, 23549, 13794, 22518, 11252, 7936, 8736, 22004, 13418, 18419, 21040, 3203, 50, 12752, 21490, 4111, 27400, 3970, 17339, 10348, 31479, 18594, 3574, 7015, 18224, 8931, 23651, 32331, 23910, 23809, 13857, 13034, 29068, 12051, 32388, 27090, 31446, 21628, 18973, 1067, 5655, 29610, 28144, 2797, 21663, 12161, 4976, 8516, 13586, 20624, 23815, 4226, 20665, 10601, 3828, 29530, 28360, 22397, 18638, 30717, 29984, 8773, 6436, 23242, 7594, 21266, 2970, 749, 23839, 15516, 30348, 23822, 25585, 10347, 15856, 15995, 4119, 31675, 26502, 6158, 15021, 6638, 22235, 20629, 30924, 23703, 14076, 32761, 13216, 30679, 17868, 7219, 10343, 30337, 2561, 15585, 25752, 13719, 11793, 28401, 7307, 8201, 22673, 22734, 19196, 602, 20812, 26226, 23793, 3076, 215, 21218, 28905, 24394, 31052, 19525, 19699, 29364, 10265, 20088, 10800, 28096, 12468, 11348, 12109, 7845, 1917, 15965, 27266, 5457, 815, 29319, 24831, 8013, 32401, 1605, 1208, 16025, 18750, 26759, 10534, 13225, 23599, 31129, 24267, 13938, 14011, 24635, 32198, 12350, 31620, 13140, 561, 18789, 10628, 1628, 12153, 7884, 21876, 24293, 2465, 31241, 29529, 9329, 16106, 32200, 17254, 20980, 29963, 13077, 20766, 30600, 32565, 18587, 19575, 19425, 25797, 16604, 12426, 28068, 6453, 7964, 27919, 21977, 26691, 20146, 12419, 29840, 5124, 4056, 26931, 10513, 21771, 7477, 7979, 6556, 6709, 12834, 24088, 14014, 5195, 4533, 21468, 17218, 31607, 29802, 27033, 16373, 10536, 3151, 19012, 10625, 11412, 18076, 28235, 29889, 14911, 13891, 32395, 20048, 6981, 11922, 25148, 26046, 1235, 1069, 28301, 24687, 6409, 11266, 19708, 3647, 9673, 12385, 18331, 19701, 2348, 4058, 1826, 13327, 26553, 21362, 24990, 18015, 6743, 14032, 13858, 19817, 11976, 15468, 1760, 26165, 10356, 18526, 5636, 4520, 13766, 1738, 4740, 3738, 20105, 3993, 7662, 30081, 23170, 24434, 8548, 30025, 6462, 22433, 26866, 29493, 11897, 30904, 22899, 28060, 4822, 294, 20210, 20239, 24670, 18777, 19303, 16229, 18511, 1867, 28261, 23778, 18901, 2453, 20822, 28770, 5930, 22606, 8444, 8974, 3608, 14718, 27604, 6494, 18010, 23863, 27748, 3944, 22958, 12283, 10703, 12839, 9250, 10216, 9861, 21338, 30989, 18922, 7168, 24713, 11934, 7995, 25910, 9378, 18273, 19694, 9807, 13429, 2319, 1062, 1053, 19532, 30414, 29024, 14228, 21096, 10056, 10509, 27035, 1659, 13016, 27807, 3697, 12178, 7866, 27690, 23143, 21125, 10804, 1541, 10791, 4708, 11032, 32014, 14169, 19193, 9229, 23350, 11071, 18295, 7844, 22963, 18495, 31178, 18967, 31368, 31237, 29735, 31035, 22003, 1722, 20559, 1729, 15303, 7643, 27911,\n18924, 13836, 12952, 19732, 5474, 30786, 21352, 13866, 21296, 21955, 5194, 16614, 5858, 20549, 3392, 21165, 21149, 20196, 15798, 13671, 11864, 23916, 28107, 18713, 4219, 24402, 26377, 1651, 16004, 11893, 29194, 9410, 5847, 2311, 18507, 27293, 28126, 14195, 10154, 3862, 9600, 7788, 6117, 25169, 14487, 14620, 3484, 20887, 10695, 1403, 20141, 8776, 24110, 11303, 2001, 20162, 12080, 24819, 24768, 14283, 18885, 22193, 22069, 23345, 11244, 11389, 20390, 12487, 24906, 13988, 29723, 22217, 9885, 9185, 29852, 18069, 30624, 11752, 31642, 30499, 29041, 13845, 14587, 29511, 21981, 28327, 16642, 21936, 26839, 12943, 21261, 11288, 6589, 14510, 5395, 24586, 30178, 26245, 10108, 8423, 30905, 13741, 30551, 21331, 19320, 4531, 19843, 14451, 12477, 8209, 24286, 24872, 22948, 22876, 2353, 15767, 15332, 24297, 6701, 2155, 29476, 4694, 12703, 14456, 14567, 23490, 9349, 2022, 10434, 21971, 19513, 25660, 19901, 13860, 20788, 22184, 8691, 18837, 13775, 6626, 30587, 2666, 17380, 21403, 1666, 9136, 9259, 17419, 17509, 29817, 14528, 27497, 5341, 8342, 2362, 3868, 1672, 14787, 10136, 4984, 3116, 12240, 5025, 24051, 1486, 19064, 19941, 5376, 11179, 18658, 32074, 22163, 10989, 7834, 5165, 12764, 11449, 9230, 20240, 25132, 548, 1297, 12252, 3893, 28646, 11673, 5870, 26179, 26990, 272, 22984, 11657, 4370, 26240, 29856, 2236, 8728, 13546, 24202, 1536, 31584, 2933, 19142, 23352, 27599, 22906, 24328, 27696, 8249, 9070, 18342, 18601, 12692, 16914, 16429, 11339, 7948, 23414, 25767, 6474, 8152, 25474, 27491, 18072, 22886, 29092, 31960, 8539, 21721, 18344, 133, 31996, 29474, 1708, 7891, 3920, 13006, 6517, 11488, 11380, 29460, 3986, 26683, 23491, 21175, 15870, 19442, 21699, 12679, 32526, 31092, 9798, 21213, 8765, 16523, 23584, 22176, 24225, 1185, 28493, 8769, 10603, 23285, 32219, 11289, 29525, 14766, 8402, 9106, 1019, 31714, 11108, 23408, 26913, 17228, 7336, 25019, 8895, 13255, 2056, 7333, 180, 11536, 3678, 19317, 25098, 25243, 8016, 18067, 27812, 31152, 31436, 20846, 30123, 20313, 22030, 26045, 8960, 25366, 29472, 28121, 8206, 14042, 29820, 31221, 492, 8998, 31774, 15935, 15932, 13699, 11100, 8236, 20154, 28602, 27882, 30829, 23233, 23065, 14347, 10470, 14905, 10492, 28797, 2566, 23740, 27014, 3159, 27485, 7244, 4897, 30074, 29045, 6944, 18852, 499, 21602, 12990, 5054, 21761, 24864, 605, 26783, 11831, 30395, 1223, 5061, 23401, 1831, 12699, 32442, 23924, 2642, 16577, 23474, 24344, 1551, 8104, 13978, 11618, 8625, 11142, 18225, 15474, 6780, 6116, 28953, 23530, 14794, 26185, 13291, 17926, 27556, 18073, 27509, 18816, 9018, 31211, 22075, 8331, 30360, 32715, 17391, 21932, 4330, 32318, 29489, 10333, 4825, 8499, 14269, 21334, 8789, 12663, 2843, 18504, 3033, 5955, 27518, 32511, 3451, 25413, 3355, 9210, 17599, 43, 1485, 28787, 785, 28687, 11442, 17813, 19733, 12753, 12497, 21402, 2198, 32199, 11578, 23037, 5941, 20459, 32291, 26454, 4624, 17010, 30, 29595, 12405, 18520, 19993, 14391, 4405, 1249, 14101, 26234, 27353, 26873, 13960, 28571, 6642, 19857, 31366, 26150, 28818, 7877, 11780, 93, 28341, 15479, 16069, 6099, 29030, 29390, 31047, 26125, 28173, 14068, 14470, 12333, 18665, 20399, 4904, 4463, 14727, 31547, 7587, 30322, 30335, 13926, 8887, 3049, 23625, 894, 30076, 4991, 22311, 13280, 31160, 30134, 26357, 3077, 26387, 24009, 12120, 28471, 18332, 32172, 19756, 24309, 17299, 28316, 16503, 18656, 27926, 993, 22202, 1558, 25711, 6570, 23428, 24177, 21189, 27716, 6098, 3265, 10780, 4037, 21919, 30321, 176, 6243, 27220, 30888, 8584, 15073, 13639, 6011, 20983, 31273, 10278, 12310, 31579, 11810, 14357, 11489, 27897, 11485, 7139, 2571, 11984, 26105, 18825, 4952, 29665, 16368, 12002, 3999, 14882, 6316, 32443, 23985, 12601, 9971, 3315, 21655, 6735, 7638, 10856, 25448, 7146, 9461, 13385, 13527, 14411, 5817, 21020, 13017, 19219, 10379, 24952, 25527, 25213, 12429, 27319, 22435, 17261, 15209, 19249, 26750, 30975, 9024, 27373, 6600, 9779, 19181, 1989, 18755, 15974, 8947, 26341, 25320, 28229, 19031, 20791, 12509, 18578, 5102, 219, 13532, 25687, 31097, 4073, 28547, 14511, 25778, 2581, 24219, 13339, 24121, 28052, 30014, 19404, 15104, 29553, 6791, 11328, 150, 2955, 22038, 13203, 13324, 22835, 5262, 23499, 23070, 9284, 16431, 22562, 8443, 25717, 12241, 8876, 6199, 13820, 32012, 19364, 19110, 15126, 21303, 4005, 8210, 30927, 18543, 32236, 32114, 21211, 12331, 1140, 7403, 18216, 12398, 32080, 20230, 2954, 18372, 15129, 21057, 19189, 5608, 20532, 25407, 18286, 22259, 876, 8534, 18988, 7165, 9337, 1622, 10537, 23421, 9233, 6033, 25989, 11310, 19349, 13180, 20740, 29278, 19099, 25844, 19568, 30629, 2076, 3334, 18002, 4811, 9108, 17952, 27707, 10220, 3717, 6093, 24506, 14384, 16316, 20378, 9236, 26853, 26493, 20614, 19583, 32445, 26585, 14349, 22719, 25796, 14111, 29632, 24516, 28161, 3750, 24180, 18193, 23418, 7005, 482, 17649, 31776, 26309, 13918, 7556, 19439, 2580, 31790, 14906, 12128, 23280, 6362, 25732, 2390, 9332, 31633, 11201, 15298, 15930, 11948, 5201, 25324, 10631, 3097, 28625, 8078, 2867, 3479, 3791, 13471, 8908, 18241, 6644, 15688, 19559, 21280, 23238, 17834, 30013, 14139, 9203, 824, 16745, 13344, 29209, 7724, 20738, 31170, 20587, 18144, 26838, 14521, 22118, 13737, 19073, 7115, 23721, 12726, 10863, 15709, 7723, 15440, 22000, 13887, 6049, 11107, 30161, 16513, 1894, 31908, 28358, 25488, 10296, 6271, 3414, 6905, 13834, 23304, 6863, 10967, 12831, 17141, 5198, 2874, 27715, 29917, 2597, 23422, 23435, 14230, 29505, 29418, 3067, 9940, 13633, 18141, 13185, 25289, 29651, 22540, 10588, 17387, 13516, 7354, 9244, 17907, 18790, 476, 31499, 28133, 30304, 6029, 17600, 26013, 11527, 24383, 5888, 14484, 14926, 23451, 25292, 10050, 1449, 8084, 10576, 916, 17548, 23560, 21311, 21554, 31317, 2247, 4065, 577, 25192, 30249, 9383, 19621, 30913, 11482, 24944, 2667, 1376, 28710, 27449, 28280, 24483, 26728, 319, 13828, 951, 11598, 6261, 29186, 9476, 27003, 12112, 30431, 16881, 30299, 9147, 27913, 17863, 14634, 28843, 8877, 19461, 1621, 19010, 26606, 25699, 7345, 8771, 8621, 7034, 30928, 27702, 23027, 28885, 12395, 25802, 14661, 12367, 19585, 8746, 12908, 30841, 28506, 1141, 19498, 30407, 19305, 23557, 13660, 13243, 19211, 6965, 9629, 926, 27820, 11219, 7989, 28576, 9157, 18105, 28114, 977, 28613, 31557, 4130, 8330, 12334, 22331, 32684, 26739, 14433, 29285, 20232, 15577, 3047, 3551, 15684, 27731, 13939, 18142, 27922, 27868, 1083, 3269, 3962, 17695, 25234, 18112, 6551, 796, 19244, 9696, 4423, 23604, 23367, 25044, 11747, 25758, 32416, 2586, 15291, 12775, 31513, 22718, 9347, 4335, 7459, 20974, 2536, 26071, 3520, 4884, 32245, 13693, 30491, 26035, 20904, 22631, 26059, 17511, 13026, 25817, 25323, 590, 10480, 4601, 21254, 27987, 7973, 4268, 10131, 9682, 31202, 25617, 4122, 26874, 12219, 3755, 13024, 30729, 19120, 23539, 32147, 9944, 4800, 20153, 7311, 9303, 25426, 5825, 15156, 21923, 19121, 12134, 7892, 14189, 5688, 6633, 4839, 12085, 24683, 22605, 30705, 11813, 20774, 591, 7512, 12228, 14301, 23255, 19233, 16133, 9639, 18089, 12630, 22613, 11387, 6861, 17614, 29654, 384, 19986, 27117, 18091, 25978, 26716, 752, 25943, 28234, 32160, 20044, 13899, 30998, 4352, 18004, 19849, 22369, 17329, 27412, 25196, 9641, 25370, 11515, 13847, 17396, 19992, 4046, 5766, 7308, 28383, 11109, 12643, 770, 31749, 23376, 6497, 11601, 31782, 8657, 3237, 22455, 17423, 27675, 17820, 25965, 17747, 22377, 18652, 9648, 24207, 20591, 4574, 15627, 32119, 4660, 6790, 6812, 15508, 4272, 277, 20938, 15968, 19856, 18430, 27130, 21483, 24364, 12731, 29312, 19049, 22046, 28674, 24070, 24342, 17769, 13767, 19889, 20720, 28250, 9226, 13576, 7680, 30336, 6623, 23678,\n5046, 9123, 15161, 9398, 5518, 20662, 9545, 13182, 27004, 19153, 31074, 10973, 8297, 24508, 11548, 4298, 9382, 27670, 22975, 22637, 13802, 9701, 5017, 21131, 8233, 903, 13334, 2835, 3996, 25554, 30083, 17450, 19614, 30204, 28766, 29214, 14397, 25121, 31743, 16585, 19669, 27295, 14260, 28108, 24528, 4275, 20468, 16613, 15555, 24226, 1022, 13588, 14371, 20569, 22268, 26100, 950, 6128, 23590, 22748, 8786, 22412, 11257, 8191, 7022, 29260, 26830, 11573, 11677, 17656, 29880, 29413, 13591, 22094, 15030, 4779, 14786, 9322, 18874, 14764, 9414, 23295, 31687, 19809, 12636, 28671, 22208, 29705, 26170, 23460, 31970, 23320, 15392, 25195, 1415, 12430, 13945, 26131, 26211, 22783, 22745, 3693, 10454, 15681, 12991, 5929, 26440, 23843, 5067, 15838, 28165, 11507, 21999, 15797, 20125, 18185, 28729, 14980, 30017, 10633, 14359, 16286, 7655, 14628, 1303, 28414, 9245, 11633, 26682, 29324, 29708, 9760, 23952, 31600, 8464, 27802, 10046, 23384, 30331, 9822, 29725, 11940, 11368, 8481, 28974, 24619, 28377, 26805, 7704, 24704, 10926, 12664, 4603, 15252, 15436, 25805, 2614, 11523, 11470, 12095, 27962, 29277, 29275, 4587, 629, 19637, 17783, 12184, 31247, 32407, 32660, 5452, 10369, 32690, 1634, 1918, 14626, 26955, 26614, 26674, 29598, 14033, 20422, 7994, 22269, 28209, 32493, 7673, 17136, 9267, 20953, 14656, 17754, 27642, 6983, 21752, 26251, 3089, 11923, 29584, 10290, 17147, 4430, 7077, 5309, 28120, 2171, 14931, 12380, 17133, 20200, 1011, 19400, 17698, 19572, 16569, 14845, 24249, 30456, 20544, 26776, 29446, 22676, 14221, 14166, 15583, 9121, 17587, 19825, 18351, 20681, 9597, 9371, 24623, 8008, 3173, 27613, 31042, 15919, 11559, 26612, 25999, 28627, 29650, 19886, 19599, 7767, 2012, 21166, 23738, 13672, 14417, 16505, 20120, 7064, 29662, 19760, 12777, 2479, 5316, 28147, 24411, 19816, 393, 21607, 2803, 10248, 9665, 9293, 29894, 11562, 28731, 12370, 32559, 19741, 19014, 1498, 19267, 14680, 31077, 364, 32675, 11879, 16003, 22182, 16272, 7742, 18892, 25800, 7907, 30011, 5186, 8474, 5988, 743, 26731, 12518, 27535, 27949, 1747, 12195, 25475, 21421, 25724, 7635, 24077, 14479, 25408, 25962, 2991, 14378, 31966, 8661, 7893, 24341, 9773, 665, 12947, 26430, 13144, 24166, 11355, 25218, 21059, 25208, 27396, 6989, 24559, 10364, 1096, 20104, 14321, 26283, 11236, 12683, 22442, 14863, 19493, 18894, 30968, 7096, 20871, 17170, 26315, 28450, 31246, 20511, 28963, 28753, 4671, 14156, 29416, 6571, 2169, 14690, 21092, 4767, 21544, 26202, 8800, 21317, 9933, 7566, 31588, 16860, 14322, 31486, 10097, 2902, 12812, 8798, 24738, 8218, 3521, 14465, 11758, 14961, 2764, 19247, 20085, 24419, 30808, 2116, 32719, 20621, 18555, 9865, 3847, 411, 10272, 6299, 9660, 17250, 31913, 27838, 1397, 16539, 9592, 17707, 9691, 32269, 879, 13618, 1385, 6908, 18302, 16939, 2784, 15446, 11750, 18562, 24001, 3922, 4440, 30617, 8009, 21774, 14666, 7156, 24324, 1580, 6192, 22871, 1209, 30756, 16795, 27600, 20751, 28387, 10366, 31587, 30651, 23153, 4390, 16661, 29386, 8135, 23178, 98, 11040, 13313, 9974, 18774, 3764, 1649, 19765, 31105, 790, 17316, 15949, 3140, 536, 17365, 4257, 20246, 20870, 1475, 27386, 23617, 28198, 27262, 15124, 360, 14126, 22736, 13566, 1676, 4741, 18267, 13948, 7150, 16192, 13683, 4064, 8196, 16574, 26789, 17435, 23106, 20568, 29792, 13102, 7272, 29903, 29883, 14993, 19086, 10398, 26498, 17652, 30144, 18285, 15325, 22595, 5751, 25463, 14579, 16730, 18439, 19092, 17225, 1748, 11712, 6211, 11709, 3088, 27475, 25325, 13223, 28925, 10913, 32369, 1032, 6342, 20578, 22768, 26707, 20020, 27257, 24138, 23496, 7295, 19016, 26479, 12681, 15034, 17880, 4158, 29057, 2551, 10126, 26926, 27510, 12439, 24888, 30628, 22986, 16462, 26326, 16662, 31448, 25850, 29946, 3653, 21785, 18704, 27116, 18860, 23250, 29270, 14312, 27183, 18623, 15088, 25625, 14499, 24238, 17896, 654, 23145, 30612, 19223, 24756, 13626, 18936, 19128, 8999, 30441, 2793, 23808, 25168, 13131, 6739, 30318, 20862, 9269, 7924, 5287, 27398, 28218, 27100, 24664, 14936, 25008, 29716, 10476, 6068, 23021, 18865, 12995, 13923, 10594, 4043, 31307, 22802, 8293, 20038, 10550, 15913, 4022, 18223, 28981, 32023, 7775, 9712, 1597, 14793, 16963, 1078, 948, 11954, 11145, 23020, 25181, 22724, 13700, 24911, 13479, 8041, 13670, 9824, 6480, 5130, 26848, 7745, 24792, 30486, 14942, 30143, 11484, 19407, 16221, 11716, 26548, 16777, 30748, 20437, 31470, 28725, 24672, 12772, 5269, 23104, 689, 30778, 11292, 28463, 30250, 17337, 12713, 22936, 24928, 31700, 19133, 3138, 14617, 5164, 26404, 19258, 24517, 8340, 13554, 26910, 18454, 10119, 29211, 14358, 29546, 8609, 8139, 2873, 26151, 19518, 31612, 26870, 28543, 29583, 26047, 32230, 25511, 22581, 14109, 29710, 31982, 9456, 31697, 30261, 7255, 19492, 4618, 12366, 29284, 24802, 1509, 16821, 14224, 14478, 12945, 3074, 32709, 12167, 8276, 29368, 31224, 16842, 14699, 16971, 21182, 9743, 24854, 12893, 17202, 16783, 32335, 9263, 27218, 21568, 16120, 25393, 23383, 23230, 2527, 7493, 11150, 28612, 10418, 8093, 14352, 6015, 8448, 9848, 10908, 16353, 14561, 18802, 1512, 12909, 23962, 21410, 13493, 28989, 16926, 30514, 22516, 15085, 2904, 18577, 12410, 7508, 24801, 30787, 28314, 3096, 2766, 11565, 16329, 27405, 10850, 12669, 7348, 3464, 15092, 32124, 26012, 26899, 2017, 24189, 1502, 16896, 25983, 9037, 25995, 10493, 27115, 20014, 29930, 17208, 20696, 21821, 11015, 32317, 23734, 10071, 6442, 11524, 22551, 17736, 5016, 13219, 20277, 22364, 15204, 15016, 31846, 5317, 16816, 31804, 11964, 19011, 24159, 31423, 15184, 23614, 32153, 4250, 747, 24665, 5598, 14468, 21838, 16478, 29496, 5419, 28736, 21305, 32087, 25742, 15334, 14317, 13300, 21436, 3623, 20393, 27550, 4014, 27305, 19157, 17596, 14533, 23051, 25702, 19230, 27920, 28515, 18323, 21784, 1875, 29864, 13187, 14227, 16055, 18030, 9104, 13081, 6759, 20705, 7226, 6403, 13819, 246, 27281, 22381, 18597, 30467, 31227, 17749, 27544, 5885, 5914, 3658, 16898, 7838, 20597, 22456, 28632, 22183, 20225, 14143, 23375, 545, 1474, 21356, 11834, 28259, 32129, 11629, 17506, 13356, 15133, 17003, 16450, 27993, 7622, 12297, 16154, 22959, 25642, 18118, 18325, 16864, 17109, 24006, 21158, 27888, 19510, 25768, 312, 4207, 25840, 27871, 26483, 273, 187, 6614, 19576, 19960, 22661, 4223, 14698, 24975, 27861, 30342, 13284, 32162, 4191, 4754, 21309, 3091, 2945, 21937, 9192, 28876, 729, 6279, 24039, 9960, 19925, 13071, 26597, 6364, 7771, 6827, 19155, 10907, 6182, 17561, 30046, 17845, 15475, 19747, 25251, 14136, 5719, 17743, 27549, 3875, 10569, 3578, 5656, 20076, 2626, 22687, 24924, 9552, 27573, 3446, 10192, 18890, 6999, 13272, 24357, 5678, 28750, 23109, 4996, 9808, 16050, 2200, 29192, 23631, 20992, 21526, 8112, 14746, 4627, 18156, 1087, 19955, 12482, 8105, 15662, 13863, 9447, 14657, 31873, 29494, 21471, 8392, 22040, 8564, 29911, 16927, 20362, 32328, 5065, 4045, 28073, 7533, 3691, 25069, 2821, 27122, 24338, 23226, 19338, 8589, 10511, 14219, 2107, 23537, 10092, 10503, 20211, 28101, 14734, 9126, 13382, 17444, 27503, 15683, 25392, 19005, 11708, 24233, 31785, 17477, 3974, 15593, 15702, 30086, 20787, 30460, 15069, 7457, 28957, 24367, 13177, 10847, 17428, 10286, 15884, 279, 31143, 12566, 25091, 32244, 20567, 1878, 13669, 21540, 18417, 19068, 24097, 29165, 18168, 12906, 32282, 80, 30236, 8017, 13801, 857, 27980, 28919, 6215, 1755, 9477, 11122, 17186, 7186, 11140, 25725,\n19403, 5952, 23050, 7281, 22766, 2711, 12387, 21601, 16555, 21688, 3306, 9810, 23121, 21592, 7399, 27312, 21030, 19268, 18471, 17036, 15522, 18639, 31752, 18393, 710, 3743, 769, 10074, 6918, 15578, 13710, 340, 15520, 15564, 20779, 22537, 20033, 26757, 28139, 22696, 30443, 18735, 15820, 152, 29268, 27254, 18730, 5735, 14223, 4834, 13992, 20860, 31204, 19335, 9920, 19343, 9530, 19916, 29196, 4823, 425, 6240, 5623, 16083, 15219, 30497, 10912, 1392, 17871, 3790, 5173, 26249, 24741, 19306, 25096, 12390, 29766, 26405, 26702, 26301, 23860, 10732, 16805, 24080, 4532, 14048, 3895, 14434, 27342, 1632, 18432, 24985, 15510, 94, 835, 17448, 6181, 21137, 21943, 19612, 18194, 24032, 16380, 14158, 287, 5944, 19988, 7142, 11740, 13895, 21546, 13990, 14944, 15829, 7577, 30282, 30028, 14843, 22130, 4146, 30555, 24136, 22387, 31290, 17212, 23468, 23877, 4929, 21134, 24700, 3103, 14681, 12622, 5375, 20875, 28354, 14981, 4467, 30899, 20548, 20658, 9733, 819, 19346, 9871, 22330, 23594, 5037, 21806, 20874, 15375, 25977, 991, 11682, 20596, 8924, 25905, 29804, 28920, 25672, 12574, 20520, 17551, 21532, 18395, 11557, 409, 5588, 2675, 9900, 17114, 20644, 15954, 21312, 31184, 4691, 13141, 194, 13620, 27150, 19561, 5425, 20726, 13230, 28056, 16520, 27737, 16536, 16669, 2418, 1607, 19727, 445, 15598, 20266, 7120, 15143, 29280, 29300, 17517, 23663, 6058, 20060, 12314, 8300, 20856, 30452, 31658, 22317, 10953, 14275, 24089, 16482, 1821, 2671, 17488, 32125, 12342, 30882, 28926, 28903, 27736, 24134, 4171, 20121, 17311, 6901, 11045, 9634, 30440, 12857, 17485, 16719, 18080, 24980, 14414, 3277, 18953, 28830, 31616, 20813, 5364, 15263, 20901, 10304, 16793, 8929, 8074, 19837, 16452, 17758, 28390, 13520, 5072, 21949, 17287, 20034, 9862, 21729, 20218, 13804, 12010, 29371, 22553, 31915, 16773, 24231, 19327, 32237, 30531, 677, 2729, 26449, 32595, 16960, 18624, 11686, 26409, 12861, 29231, 9823, 16832, 30534, 17957, 15321, 18320, 3341, 25147, 28565, 19534, 28821, 16041, 3701, 8537, 14234, 7632, 11371, 19813, 24551, 1322, 7313, 15687, 5404, 11525, 15645, 2031, 18163, 16458, 26864, 2196, 32762, 8966, 21565, 12247, 31325, 15206, 1429, 6378, 14233, 24385, 28195, 8689, 27636, 28615, 20560, 13461, 25175, 4792, 1129, 14829, 26212, 25772, 18077, 11839, 4378, 28836, 7978, 12558, 15445, 338, 30222, 6792, 7187, 26616, 20371, 19307, 30262, 392, 31311, 9666, 24899, 25458, 4314, 26408, 21950, 252, 28016, 3073, 32406, 1478, 26413, 8730, 539, 31951, 16449, 6886, 21647, 24893, 22669, 20914, 18234, 12741, 17779, 19363, 20775, 30415, 15915, 25240, 16651, 24251, 26056, 283, 13001, 14406, 8899, 16723, 23513, 28599, 29712, 31666, 21077, 31326, 6957, 32079, 4831, 20981, 31430, 17497, 11800, 308, 23799, 32154, 28007, 15656, 7381, 20054, 23758, 9065, 12352, 7876, 20234, 22049, 18346, 16170, 1895, 31796, 5744, 11522, 2889, 30603, 30931, 7687, 19524, 6669, 15195, 15160, 9069, 21618, 26817, 6086, 23970, 26070, 18485, 22209, 586, 946, 25427, 688, 3194, 12621, 1295, 12590, 27640, 28845, 7041, 18317, 21429, 22228, 200, 24965, 12736, 22340, 29701, 11761, 22641, 14997, 5791, 19214, 21368, 25140, 27723, 8143, 8479, 14454, 4881, 19667, 25417, 5966, 27355, 8375, 15093, 4270, 10404, 8673, 11587, 30012, 24093, 29267, 21832, 30500, 20360, 9718, 6752, 25127, 28008, 31890, 13568, 5703, 12829, 13002, 30895, 12819, 7250, 5135, 12269, 17085, 22896, 16091, 30851, 1240, 12960, 24859, 23526, 26432, 7243, 30398, 1021, 3841, 14832, 18754, 6014, 24060, 1889, 14009, 7823, 26927, 31206, 19227, 8806, 25980, 8317, 19030, 22979, 490, 26322, 32537, 191, 4758, 18226, 5698, 28584, 31159, 11815, 25180, 6039, 17556, 904, 1250, 14543, 23348, 24794, 2086, 20379, 1791, 11077, 102, 21533, 10564, 3888, 19431, 1590, 30471, 28798, 3307, 27514, 10271, 10242, 9724, 1001, 25537, 4307, 30126, 25963, 1739, 24579, 31140, 29675, 23480, 1830, 16716, 16459, 12616, 16672, 15738, 11035, 20398, 30097, 12174, 28699, 29282, 3150, 8267, 19389, 20345, 3214, 26734, 7302, 14751, 32034, 30868, 15197, 12169, 4052, 14811, 27291, 1301, 8265, 286, 23580, 3462, 9985, 25525, 13364, 4083, 7032, 6775, 5564, 6991, 18646, 22446, 8656, 18109, 2528, 26132, 18641, 32083, 24941, 13282, 29674, 32099, 12006, 22967, 20612, 95, 18767, 32321, 10064, 25984, 23459, 1043, 18602, 12485, 26140, 22188, 27722, 29915, 18188, 21500, 8436, 27287, 22375, 5923, 4105, 25814, 74, 17764, 7341, 7275, 28790, 28730, 31575, 24590, 3046, 13638, 13332, 28738, 26353, 5710, 19686, 19009, 18524, 6216, 2756, 28241, 29190, 12377, 22115, 26081, 26085, 6947, 8568, 3378, 21815, 1057, 12971, 22467, 24936, 30881, 21150, 26027, 3289, 19145, 22926, 27738, 20018, 17174, 8030, 24636, 14860, 9661, 27622, 19726, 3453, 18650, 17429, 30575, 30949, 13464, 18979, 19486, 21200, 11625, 21000, 2195, 29303, 21918, 17249, 28639, 18977, 404, 25934, 15592, 31895, 8559, 17115, 9623, 2079, 1336, 9044, 31334, 17763, 23913, 18733, 3571, 19234, 10826, 26978, 5329, 1910, 21606, 11530, 23007, 8679, 19316, 2318, 24655, 14148, 1063, 16706, 451, 21988, 11882, 12471, 17270, 21582, 11331, 11537, 20934, 1453, 4548, 15101, 30404, 20171, 18982, 30613, 14491, 9909, 16187, 19639, 28247, 26447, 15746, 23303, 17356, 15242, 24717, 32310, 9238, 12659, 18622, 31553, 16454, 6953, 16352, 1800, 19085, 11414, 17038, 23995, 9627, 78, 16325, 25445, 2055, 562, 29296, 32465, 978, 713, 13200, 22145, 5079, 19225, 19835, 14027, 11000, 7707, 204, 27181, 28020, 13125, 10281, 1803, 2495, 1182, 22337, 26193, 20715, 28146, 16438, 12858, 1306, 18499, 21036, 26300, 19260, 22814, 8668, 29467, 21349, 30127, 27954, 19087, 14194, 23853, 23752, 32088, 1646, 25835, 7506, 20377, 11403, 1689, 10437, 29035, 5459, 13421, 20486, 19324, 11185, 17928, 2517, 30162, 8865, 17030, 24889, 25854, 15405, 26208, 23229, 26863, 7051, 23896, 687, 21316, 26930, 18270, 14245, 30098, 28775, 21893, 13731, 2457, 27924, 25461, 14682, 10153, 3422, 17921, 24881, 20986, 18257, 14686, 32594, 26032, 21023, 29069, 15432, 22962, 17155, 5642, 29641, 19503, 16531, 23087, 23241, 2408, 765, 16393, 19200, 1116, 24777, 15330, 13249, 11916, 17169, 6887, 17397, 26571, 2888, 16692, 10875, 17289, 4908, 24148, 29977, 20963, 19879, 7102, 17357, 7584, 7377, 8356, 6560, 5577, 2416, 13228, 23973, 16836, 28702, 29661, 10947, 17814, 224, 1658, 22064, 25872, 22543, 1307, 4232, 5664, 3193, 27239, 18714, 4808, 20254, 29615, 6076, 19759, 25131, 2179, 28448, 29574, 14006, 19671, 11645, 9139, 3692, 11203, 6977, 19836, 13391, 27762, 11814, 23089, 18192, 10308, 24329, 19319, 23609, 26564, 8981, 13788, 17897, 1161, 25468, 22555, 22575, 6726, 22267, 1838, 27657, 1288, 9351, 22227, 27739, 32300, 19358, 3979, 32216, 30544, 10551, 17795, 28127, 28827, 9635, 14038, 17197, 27409, 26241, 12480, 11004, 25609, 30825, 11944, 593, 19238, 23150, 20672, 22247, 23084, 27039, 5838, 17351, 24533, 13184, 11161, 7999, 26822, 24814, 28472, 5661, 32006, 17001, 25754, 27973, 8818, 4785, 31692, 24595, 23012, 278, 26774, 3152, 10744, 23881, 10349, 17390, 20764, 11068, 18807, 9518, 10082, 27139, 29659, 12175, 32682, 32712, 17744, 17595, 8749, 19521, 15365, 19597, 29385, 3947, 14461, 22081, 15036, 22206, 15515, 4168, 29348, 24556, 30738, 15234, 25483, 29689, 11658, 10788, 29536, 17143, 11774, 32538, 15771, 10420, 25832, 8312, 1572, 24584, 32183, 12901, 30021, 28975, 26176, 13106, 29764, 18151, 20090, 13466, 14599, 6732, 12209, 17714, 15011, 26319, 15120, 3493, 4934, 29844, 28451, 25410, 3910, 8536, 29185, 2360, 21626, 27160, 26003, 12776, 23359, 10644, 25272, 4529, 21723, 22625, 6075, 6852, 22098, 5891, 3219, 31117, 20932, 20680,\n5868, 25535, 4942, 1074, 14173, 28239, 25747, 14570, 1501, 14925, 26044, 26144, 14660, 24566, 29904, 28196, 13108, 29979, 9409, 1959, 22131, 19350, 81, 24922, 15397, 13907, 28752, 10512, 16579, 18411, 16283, 27697, 3733, 1510, 12261, 20245, 14379, 10051, 29767, 3007, 13835, 29741, 28441, 11057, 19987, 30570, 27092, 25546, 30977, 7939, 20717, 2005, 23253, 7304, 18856, 16476, 16995, 25597, 1189, 11667, 32653, 18903, 9064, 18500, 14276, 2805, 9475, 29816, 28066, 19376, 14623, 664, 15588, 794, 13372, 9642, 26427, 814, 9581, 21118, 16722, 10655, 12149, 26163, 11336, 19740, 22775, 534, 30067, 9304, 30681, 32094, 1744, 28033, 20281, 25450, 2274, 4039, 17753, 4220, 30223, 10741, 9219, 12354, 21469, 5185, 12220, 26011, 20767, 9115, 5321, 6084, 18117, 12965, 13215, 19600, 14131, 12466, 15841, 758, 21912, 1519, 29836, 12552, 3199, 3222, 15843, 4394, 29738, 32205, 10061, 30194, 9731, 1279, 15531, 17404, 23313, 6000, 23099, 18179, 29423, 1614, 354, 27036, 7263, 15305, 17183, 1440, 9809, 14864, 15755, 29477, 15647, 29299, 17335, 18617, 29575, 22283, 31716, 26276, 5704, 24154, 6104, 12132, 9962, 1805, 242, 19590, 18191, 28665, 26903, 23653, 26285, 29646, 22203, 14097, 4051, 13961, 29201, 11783, 20163, 13488, 7696, 887, 3496, 5104, 18539, 3316, 8096, 28732, 16258, 7510, 12049, 8110, 29826, 23273, 27243, 11466, 13474, 31508, 23935, 7758, 28497, 29590, 8051, 16679, 649, 5405, 18513, 28221, 24502, 29222, 24371, 25612, 15233, 17637, 11055, 17400, 21467, 22723, 28871, 24707, 7388, 8447, 29349, 19985, 15631, 2620, 27914, 22545, 21807, 7191, 8669, 23096, 26010, 26261, 3655, 15855, 25569, 17558, 11939, 8561, 23237, 16270, 29266, 32040, 30465, 7428, 1114, 6603, 13541, 17298, 17507, 20347, 20850, 23297, 16376, 3002, 1132, 29663, 12810, 23649, 19648, 29147, 25244, 17370, 31308, 29070, 973, 4560, 21668, 24068, 23503, 21268, 23629, 19930, 15361, 3191, 24691, 11364, 18947, 24617, 15241, 19937, 9517, 13901, 23728, 29243, 8801, 9140, 20628, 10641, 2462, 20305, 23086, 14457, 8574, 5098, 2141, 24685, 10960, 30933, 11037, 18746, 31500, 20763, 12685, 24496, 26684, 25907, 17045, 15014, 5429, 19315, 32602, 30526, 28857, 11222, 8345, 7347, 6547, 27367, 13074, 18660, 10917, 14488, 22451, 29394, 2543, 10445, 23574, 29652, 1640, 15134, 22207, 12657, 22319, 16758, 16472, 15425, 26678, 2276, 26558, 25611, 23524, 18486, 6445, 19807, 9795, 6715, 16357, 22103, 21684, 19385, 16936, 7765, 21586, 341, 12116, 11796, 16121, 4453, 10659, 28562, 18349, 20926, 17364, 13221, 4543, 9680, 110, 31065, 11360, 22585, 4563, 17515, 15736, 27750, 16535, 4540, 365, 30065, 931, 31064, 15511, 16658, 23682, 27309, 7154, 22772, 6588, 15672, 18169, 26215, 9967, 15402, 17532, 15734, 6713, 1732, 13636, 10191, 22100, 16581, 16526, 31968, 11413, 24995, 17445, 27097, 25955, 14602, 24938, 16809, 30308, 22919, 16829, 4669, 13512, 15900, 23857, 27893, 20008, 24086, 14051, 1070, 12035, 10983, 23136, 31155, 9619, 30554, 3595, 3463, 4482, 5176, 28669, 6514, 7923, 12828, 30725, 32601, 19279, 14178, 15202, 28676, 9439, 20369, 20687, 21910, 31416, 25139, 16136, 20441, 24313, 17247, 1733, 13884, 24170, 3941, 13151, 18347, 27127, 23597, 1564, 29599, 31250, 1077, 28408, 13665, 11491, 6092, 26310, 9874, 1095, 15673, 12969, 31866, 25307, 8167, 23932, 21405, 2191, 27615, 28983, 27840, 16210, 10307, 9511, 10528, 16725, 4597, 12414, 5960, 32110, 1218, 25775, 26231, 19321, 15434, 23582, 2546, 15951, 18548, 28557, 9109, 493, 11372, 9291, 4081, 15513, 19722, 6131, 17884, 29232, 20195, 13410, 26541, 18288, 14303, 17918, 533, 15697, 2767, 1222, 15633, 17796, 15470, 17886, 20607, 20927, 29554, 3736, 18925, 10952, 3342, 10159, 15097, 14453, 32108, 30772, 23536, 29046, 30037, 28351, 2808, 1940, 28634, 13029, 28248, 31690, 7749, 23420, 21640, 26882, 28877, 4504, 31731, 21861, 26503, 16553, 23033, 19693, 10294, 25571, 28421, 30190, 27318, 117, 5143, 436, 7865, 24235, 5192, 17284, 30263, 27176, 1015, 13059, 9532, 5211, 3095, 25957, 6047, 26655, 8348, 29482, 7794, 29570, 20732, 24719, 22472, 25482, 3117, 24443, 16232, 30754, 22577, 29780, 18149, 6119, 2894, 17029, 13545, 14420, 9089, 2757, 14138, 21995, 8506, 29051, 1542, 15751, 22251, 5401, 20233, 20909, 29656, 32367, 29028, 30530, 19858, 3754, 2983, 30374, 961, 31203, 23077, 23927, 6121, 4871, 26220, 16487, 18586, 17538, 6997, 14791, 11973, 19943, 23405, 25986, 12267, 8726, 7938, 19186, 21509, 17246, 1992, 7080, 13511, 28452, 8270, 23011, 30736, 28244, 22042, 3581, 19632, 31424, 14467, 16775, 2126, 32116, 6465, 7409, 11584, 29431, 9380, 11952, 15960, 8150, 10062, 32109, 32670, 8173, 31409, 29181, 30247, 16067, 5024, 28338, 4615, 22009, 15478, 24103, 15391, 570, 20212, 17719, 11591, 25228, 17325, 15162, 23323, 6079, 22746, 6553, 27653, 19850, 10111, 28946, 14418, 12542, 15360, 23750, 26501, 28566, 22333, 2919, 23676, 164, 19538, 8792, 2759, 10593, 26975, 15028, 13680, 18580, 21449, 3290, 16993, 2473, 18975, 24795, 18431, 3663, 18603, 14886, 23103, 12335, 24653, 31006, 23968, 25028, 23002, 27282, 26797, 31021, 7351, 25891, 23067, 8157, 15594, 13709, 18368, 14814, 27202, 5637, 25856, 15507, 26127, 6384, 30314, 4774, 23221, 16200, 15326, 1517, 9043, 13012, 2084, 19794, 28847, 10259, 27826, 10627, 24436, 4805, 13060, 4492, 3405, 21829, 31696, 25161, 16087, 2378, 26993, 31899, 6443, 29895, 25382, 23732, 17214, 27082, 23406, 12721, 25638, 3810, 15211, 5957, 3715, 18006, 20473, 18642, 10212, 30914, 7, 13984, 2299, 9910, 28779, 12243, 29067, 27895, 32642, 31255, 16978, 21675, 6756, 23114, 24067, 2859, 24731, 1644, 1435, 17413, 17805, 3439, 9212, 16747, 7365, 16617, 22930, 19130, 16852, 14104, 19054, 31965, 29021, 22034, 3538, 11404, 8070, 12758, 9379, 5948, 29220, 30746, 12442, 17638, 17348, 21972, 27995, 9705, 1884, 3953, 5397, 19075, 17277, 12872, 17323, 16788, 31822, 15556, 20777, 3294, 22883, 31235, 25299, 24167, 19956, 2941, 18579, 19256, 756, 23430, 16471, 5076, 28251, 28893, 14498, 21049, 21130, 19033, 24905, 22389, 27639, 28590, 1617, 8224, 31947, 27991, 27516, 14974, 28863, 26976, 13542, 32486, 11637, 25224, 21973, 14175, 11887, 14701, 9543, 5533, 9804, 25950, 11997, 4507, 16610, 26752, 16947, 23823, 22261, 31023, 7654, 14013, 22025, 28190, 19768, 15065, 16032, 7444, 20995, 30885, 22370, 29429, 24055, 11421, 17196, 25941, 1928, 24446, 6381, 18907, 29793, 18879, 22215, 20772, 12532, 4657, 20021, 19076, 4962, 21139, 2468, 2818, 25873, 12641, 1567, 24310, 7097, 25809, 1742, 30052, 20492, 8713, 11768, 848, 17996, 3575, 9736, 3182, 22697, 17722, 6074, 29762, 31013, 28622, 14338, 28397, 30740, 18339, 29333, 31358, 10899, 29305, 4451, 14848, 19228, 12743, 14389, 17057, 8083, 29523, 26887, 24430, 22628, 27051, 17821, 13718, 11042, 8509, 22695, 23959, 23641, 14851, 27968, 11284, 6180, 29117, 13609, 4376, 3082, 15844, 367, 28424, 8813, 15640, 29484, 15894, 16275, 31150, 16390, 20894, 7955, 27797, 13738, 20293, 23911, 109, 12853, 13397, 24577, 5295, 32469, 22135, 24935, 31963, 24598, 25425, 7957, 22362, 23802, 11590, 30615, 4812, 20659, 9366, 21559, 7327, 13368, 11539, 32030, 892, 23756, 3367, 3934, 16763, 3660, 32313, 20582, 15657, 28461, 23547, 30750, 7766, 12478, 8048, 4239, 520, 28945, 25457, 24622, 19173, 29037, 4777, 14356, 23842, 22614, 15978, 12234, 21835, 23456, 28507, 18033, 1179, 31389, 14113, 20524, 16291, 18412, 21701, 17785, 5918, 22125, 23561, 26622, 22445, 31724, 25056, 24185, 22985, 8273, 22664, 5359, 16266, 18858, 15501, 8988, 7238, 16580, 14288, 23854, 30218, 10543, 913, 17660, 15983, 20219, 31016, 8349, 2381, 24797, 620, 5782, 29687, 18609, 15776,\n10461, 28404, 27101, 22576, 14412, 10634, 29814, 20797, 15737, 17642, 22402, 12986, 13711, 964, 5307, 12286, 13816, 24721, 22083, 3985, 11931, 22039, 1111, 9307, 5277, 17700, 31297, 18096, 8433, 11868, 15419, 19440, 10326, 12101, 14110, 9200, 7847, 11867, 29281, 26294, 380, 18654, 17160, 6208, 31324, 30702, 9352, 31254, 15663, 13952, 5421, 2496, 11415, 16241, 4553, 11856, 17967, 32752, 28806, 28308, 1870, 15964, 31898, 17927, 14120, 21106, 10029, 22854, 22304, 32260, 9276, 27275, 23424, 6681, 27728, 26167, 5074, 24253, 10990, 18948, 29060, 12658, 1470, 3006, 19896, 438, 31447, 21170, 11919, 22887, 29101, 657, 12260, 22845, 27402, 31986, 11322, 26763, 22380, 30893, 11982, 8772, 24011, 5399, 3389, 29914, 4588, 5267, 13983, 21061, 24468, 27814, 28459, 15514, 10692, 3361, 10766, 13999, 9534, 6699, 2733, 31528, 25749, 3570, 19441, 16810, 21121, 32532, 13160, 21262, 17881, 238, 12885, 25499, 4096, 25388, 26561, 9213, 2806, 22464, 19646, 26565, 7710, 4160, 8316, 10373, 30511, 32325, 2564, 17272, 17317, 20701, 19844, 16655, 2117, 25644, 15488, 28123, 22058, 23110, 8242, 2215, 16012, 12792, 29020, 28271, 27933, 23701, 22846, 1380, 21251, 16219, 25156, 18498, 10957, 21394, 24198, 31803, 8649, 12646, 11325, 24867, 17263, 29539, 21600, 28291, 5168, 12914, 2601, 26174, 3364, 18322, 28329, 27877, 28771, 8897, 5151, 2639, 24753, 4290, 2962, 24505, 18299, 31969, 8263, 17815, 12257, 26445, 18050, 1642, 12070, 10201, 20573, 24613, 14212, 32223, 19719, 19300, 8821, 26420, 29532, 25490, 21169, 24507, 30594, 31919, 24428, 31765, 23818, 8215, 28635, 3300, 10289, 30184, 18308, 32385, 19434, 29153, 258, 12627, 28527, 28663, 9035, 4331, 23095, 7537, 25926, 31301, 5127, 1213, 11899, 25949, 11281, 5802, 15135, 5971, 28735, 3383, 28537, 3759, 16137, 13622, 20516, 26989, 25159, 12976, 12031, 16416, 21209, 5232, 3489, 13708, 15301, 27232, 22712, 12226, 20395, 957, 18453, 417, 31167, 28345, 18215, 13233, 20973, 21488, 16212, 2908, 12649, 20677, 22315, 17531, 28678, 14198, 3535, 31330, 13383, 5153, 19749, 22041, 25437, 9176, 27874, 20167, 4382, 18203, 14374, 27096, 2861, 23244, 9799, 27619, 25541, 19132, 458, 2091, 30315, 19938, 23131, 28269, 25297, 20397, 4849, 8952, 29786, 12165, 32311, 31767, 8927, 2736, 3433, 28098, 20186, 1387, 17529, 8426, 15297, 26217, 16365, 27381, 27810, 16699, 26942, 3627, 19755, 4913, 25829, 1467, 5346, 18441, 11464, 25418, 7280, 19302, 30675, 3325, 11724, 16668, 13340, 3346, 32423, 9829, 6007, 26726, 18180, 31710, 23898, 11298, 25350, 24500, 30732, 32177, 9218, 1480, 31415, 29479, 8972, 5196, 10334, 12742, 30455, 8223, 2494, 9242, 1312, 6802, 20504, 12786, 4731, 17857, 18384, 10578, 21764, 24656, 17930, 21464, 16473, 25275, 1372, 11409, 32347, 12055, 10978, 30039, 30804, 7309, 19416, 29582, 17343, 20484, 3363, 5304, 26888, 4968, 10381, 17257, 13806, 16310, 27917, 32509, 20936, 17152, 8886, 20438, 15491, 27246, 17790, 21572, 26512, 23415, 25681, 949, 8614, 15775, 25517, 21144, 13687, 25464, 7576, 14772, 24150, 12130, 6678, 3923, 32247, 28886, 10173, 1471, 7199, 1398, 13450, 31930, 16932, 31578, 29010, 18306, 25435, 22994, 26594, 6649, 315, 1609, 24462, 16929, 22, 26784, 23864, 23472, 14555, 16171, 31698, 3588, 24523, 5548, 23807, 15076, 18918, 30018, 11941, 8114, 25063, 18231, 2038, 10306, 12064, 15430, 9399, 14841, 25225, 31099, 23812, 9423, 31938, 5077, 13116, 21560, 7690, 13662, 17320, 14247, 23871, 16711, 21102, 21058, 30166, 16180, 9875, 23268, 14525, 2689, 3108, 31000, 5350, 19061, 31725, 30104, 32695, 12821, 32194, 31474, 29968, 5302, 20388, 26997, 10352, 10760, 8620, 3488, 20213, 4259, 32650, 31174, 15043, 4078, 29526, 19746, 14090, 14675, 13369, 7430, 12964, 27904, 23001, 24053, 8225, 27458, 27383, 16319, 14856, 27559, 25194, 12230, 2727, 25081, 32491, 10774, 16496, 5759, 24660, 13676, 29668, 9393, 18986, 23410, 18354, 20907, 14874, 19641, 2648, 28067, 18340, 5508, 987, 23642, 26378, 6801, 3136, 30699, 10621, 16837, 27981, 27425, 30466, 30254, 24733, 15971, 18867, 24662, 10683, 31523, 28972, 5896, 30892, 16685, 2836, 13251, 1438, 24896, 11311, 3870, 20300, 24139, 13358, 21021, 23709, 808, 23868, 9355, 16029, 18458, 26710, 31886, 23429, 28375, 22419, 5583, 6054, 16847, 22310, 25640, 1184, 23274, 14800, 4206, 18644, 15981, 16767, 25088, 22827, 18770, 16997, 28799, 31589, 24062, 4760, 21179, 22763, 19210, 21938, 18808, 31061, 9471, 23892, 5480, 22119, 7500, 13130, 8416, 19025, 32723, 32133, 20824, 19259, 31537, 27994, 25540, 25567, 197, 29913, 28721, 11155, 5219, 26262, 7318, 20428, 2427, 23009, 11811, 32571, 3107, 3583, 16667, 15997, 27094, 13889, 23814, 18993, 2487, 16068, 17883, 20226, 10772, 5526, 27323, 2321, 28063, 3118, 24821, 26280, 31604, 31401, 9258, 11542, 14821, 19237, 29184, 3924, 17043, 18266, 12580, 27763, 15372, 10496, 17606, 8228, 22465, 21282, 27614, 11241, 6360, 15116, 21484, 2441, 12159, 25588, 2361, 31728, 18148, 23028, 23010, 22280, 1156, 14941, 19899, 13346, 18729, 61, 16670, 24282, 12434, 19454, 18818, 11006, 27454, 24274, 18949, 19273, 20817, 17567, 30619, 18537, 13089, 240, 28574, 112, 7536, 23751, 11717, 15010, 19171, 4260, 7998, 10303, 16785, 18653, 24298, 10619, 11174, 27591, 18450, 20427, 18078, 30802, 22941, 3792, 20059, 20049, 17105, 30132, 25048, 29318, 2035, 4455, 4292, 14696, 21274, 6056, 27824, 24509, 19610, 7188, 28867, 15552, 3773, 14444, 14251, 20765, 5318, 21277, 11246, 17024, 12554, 23470, 16605, 23541, 11789, 4759, 22901, 15112, 17307, 17474, 372, 2271, 14476, 8364, 28701, 11583, 15284, 2008, 10260, 14554, 17948, 18492, 20844, 27087, 22915, 5325, 4428, 14350, 24448, 3892, 17955, 29682, 18751, 28187, 7814, 17726, 32082, 15994, 1712, 9459, 9457, 11760, 17266, 21279, 8214, 32464, 14191, 26116, 17770, 28591, 22580, 13366, 23306, 15180, 17007, 20009, 10433, 27250, 21769, 22289, 1600, 15549, 5432, 13800, 2062, 21946, 3324, 18407, 28379, 27789, 16862, 11118, 5612, 14500, 17693, 24022, 21571, 27086, 3633, 32375, 30211, 6771, 307, 11446, 1153, 1315, 15858, 842, 12204, 31668, 13661, 16690, 11085, 2929, 21105, 12217, 21588, 15704, 284, 16346, 17677, 18546, 27788, 8453, 21397, 15985, 31131, 30961, 15714, 9669, 23133, 27767, 12403, 29788, 20906, 20102, 23184, 805, 12476, 878, 31291, 17756, 10895, 15080, 31655, 299, 15888, 10726, 20530, 16799, 7631, 12202, 27073, 27413, 23608, 29375, 3680, 9160, 740, 26661, 24038, 13779, 13535, 20414, 24754, 20248, 730, 25267, 29933, 18394, 13812, 2233, 22504, 25723, 24873, 5986, 16611, 3814, 7869, 14865, 19209, 21299, 21068, 3345, 23343, 27269, 26088, 5574, 30181, 3533, 31125, 17166, 29970, 27822, 19884, 27984, 22036, 20811, 30022, 2384, 15099, 17149, 23507, 22448, 1782, 10884, 13128, 23600, 17018, 9480, 27148, 20905, 3229, 8469, 17544, 3024, 22582, 13323, 27452, 4746, 29551, 25959, 674, 22175, 27129, 5292, 22248, 26156, 15041, 6429, 19588, 14809, 156, 9959, 26519, 17200, 4236, 24497, 9837, 6198, 23722, 15551, 3820, 2537, 7227, 13561, 31954, 32060, 12037, 26951, 4367, 4334, 310, 21916, 19137, 23130, 9913, 19015, 5724, 22204, 14149, 30897, 17617, 9656, 306, 22028, 22452, 22152, 38, 18027, 18689, 28866, 14342, 22181, 7235, 15685, 24678, 27460, 28156, 21583, 17002, 14965, 23019, 14003, 28275, 20948, 23177, 30988, 5861, 26288, 16103, 25922, 2693, 30328, 32485, 10172, 18220, 32046, 31489, 11345, 16563, 5990, 20586, 20273, 3247, 7488, 16072, 4526, 26270, 26019, 20653, 2482, 14029, 32056, 13258, 17582, 29178, 15163, 5739, 27180, 31341, 26736, 26482, 1099, 19546, 18014, 29534, 17463, 18233, 30295, 23803, 483, 19182, 10186, 16382, 25326, 25280, 6406, 169,\n16078, 17989, 13679, 17172, 9893, 3060, 14306, 18056, 18029, 1647, 21924, 14273, 28036, 16009, 15396, 20011, 615, 16557, 26411, 32381, 10044, 14432, 18745, 2961, 5411, 25440, 13893, 17768, 30922, 7875, 6892, 28890, 30710, 5833, 25648, 20081, 21643, 29404, 28043, 350, 25074, 23933, 25344, 8420, 30255, 23887, 28199, 19107, 1107, 25601, 23996, 12638, 23708, 31218, 24460, 30559, 25811, 12122, 25339, 9821, 1212, 13856, 4776, 10769, 17402, 8923, 13967, 5048, 1877, 2459, 16167, 26407, 3188, 24734, 24183, 31492, 9368, 14396, 22358, 9723, 19476, 28193, 32179, 4676, 32612, 9295, 25238, 19042, 30435, 17492, 2788, 5977, 3612, 18100, 17052, 7143, 6818, 23272, 23031, 15466, 32207, 13434, 6774, 17358, 15850, 2817, 5836, 21294, 27711, 29655, 8216, 15998, 27873, 17935, 6976, 14783, 27680, 23506, 27307, 23008, 1855, 17936, 2252, 9965, 22572, 266, 2616, 2230, 31371, 11895, 27288, 5273, 8842, 14187, 7383, 13753, 17672, 19870, 1117, 32022, 25583, 17602, 9927, 4771, 22027, 29874, 11936, 27041, 2761, 23782, 2471, 12710, 24017, 23360, 28521, 8450, 30912, 19665, 7025, 1834, 25643, 10387, 21371, 24356, 7442, 5264, 16797, 27326, 9013, 12156, 5799, 21956, 897, 6151, 13562, 111, 27214, 5178, 32018, 18357, 16201, 7094, 3747, 12871, 30273, 30796, 9272, 5911, 14515, 2605, 2779, 8560, 16615, 3009, 24806, 24204, 7236, 24624, 13796, 26195, 6974, 19277, 3374, 30079, 1598, 13278, 17068, 18274, 21075, 13735, 218, 24530, 10020, 6090, 30535, 4350, 1463, 13658, 18401, 10941, 32161, 23685, 15382, 631, 16609, 28226, 24953, 22321, 4007, 11370, 32235, 16305, 28455, 29432, 31490, 25170, 3165, 25701, 17793, 13667, 27265, 31188, 13572, 23094, 3207, 11087, 22136, 28741, 32706, 10857, 4965, 5010, 1128, 32169, 1193, 30536, 18184, 13616, 29084, 8407, 19703, 9586, 16638, 19846, 12265, 28813, 18157, 27718, 30391, 19860, 25666, 26772, 32479, 12562, 14315, 26372, 30464, 16481, 30711, 19151, 4437, 10545, 18143, 20929, 11617, 22907, 16975, 7465, 18839, 15442, 11116, 23098, 7902, 8629, 15553, 511, 31652, 23125, 5349, 17490, 4786, 17046, 26123, 30068, 28716, 18153, 1098, 942, 17962, 12465, 3352, 18567, 22172, 21498, 25431, 22057, 2275, 12538, 27456, 18878, 28542, 28106, 2405, 9268, 21707, 21048, 1574, 29818, 20252, 9504, 26110, 24835, 21681, 13581, 9650, 30203, 31379, 21222, 10118, 26568, 4011, 15770, 22841, 32677, 28311, 29430, 19347, 24482, 31305, 27343, 19180, 31883, 24971, 24780, 29775, 6534, 12856, 21696, 23902, 14795, 32671, 31786, 13305, 18398, 4286, 12802, 10566, 14130, 18688, 32155, 19839, 32472, 22670, 6045, 28976, 30233, 28966, 12446, 19138, 28509, 20554, 30174, 18921, 5029, 3319, 21225, 1960, 16314, 32053, 1090, 2394, 7364, 26796, 24940, 28653, 7870, 8140, 2576, 24181, 588, 32185, 20754, 11926, 20954, 25744, 6620, 20872, 6539, 20436, 3377, 26836, 28061, 20796, 7623, 12201, 17835, 1285, 22616, 21620, 27894, 11675, 20466, 30507, 30397, 31336, 13173, 4979, 8845, 13052, 31289, 18137, 32610, 16412, 5935, 22523, 16826, 24761, 8302, 24615, 12845, 27791, 7292, 16656, 31193, 17788, 6248, 30357, 18236, 24913, 14903, 5212, 18558, 24109, 16511, 27260, 7228, 31397, 31927, 4967, 15975, 11009, 9092, 21927, 5931, 32284, 24843, 23861, 6672, 23832, 16892, 6350, 7157, 14281, 5083, 23982, 23880, 17321, 4702, 30309, 30860, 21146, 13011, 24463, 23829, 13544, 30930, 419, 2375, 29875, 25084, 17102, 21510, 14768, 23686, 28916, 25691, 2490, 13066, 20430, 26760, 18164, 13628, 26985, 21666, 5387, 8427, 23083, 11987, 8289, 12332, 2046, 17081, 11218, 21804, 10244, 30847, 26078, 9888, 31354, 29974, 17037, 10392, 9211, 5442, 4707, 21239, 10577, 3806, 14103, 32266, 21521, 21339, 23312, 17844, 16445, 26026, 13867, 18854, 16818, 14304, 5683, 14563, 13547, 1765, 19571, 24396, 22980, 27730, 32649, 23771, 7060, 31066, 25773, 16166, 24100, 4842, 26247, 15540, 8739, 22877, 18776, 21672, 4710, 14346, 29544, 29027, 28512, 1298, 11596, 16900, 12072, 22146, 11206, 18406, 10572, 24340, 7652, 20563, 18997, 6725, 3190, 23659, 13442, 8025, 21231, 14574, 3369, 2014, 4666, 2325, 16976, 22440, 20958, 14429, 21965, 31226, 16631, 32678, 27900, 4512, 16602, 24388, 17976, 29459, 9207, 17180, 8002, 27928, 8220, 20019, 422, 3785, 21566, 24634, 21014, 22475, 13212, 8058, 11268, 20794, 25677, 27324, 3331, 15299, 16759, 26499, 25641, 17455, 28405, 23385, 16, 26049, 22366, 19540, 25185, 25209, 22751, 13808, 25557, 26008, 6632, 23915, 21755, 16042, 10701, 16149, 18353, 31359, 9580, 9852, 26704, 5810, 12954, 18207, 16665, 26069, 14706, 26145, 12179, 6371, 20564, 26905, 22655, 18155, 20314, 20984, 24666, 25362, 9989, 11354, 19236, 15680, 28046, 15679, 8868, 3937, 28219, 11961, 23720, 30085, 25830, 2555, 21203, 18961, 6148, 4181, 12445, 29240, 31383, 6389, 8137, 8156, 29702, 26380, 6196, 921, 27406, 23969, 13969, 27706, 1246, 5463, 18083, 31809, 22410, 9036, 23889, 25581, 26022, 15853, 18956, 14761, 9794, 3149, 14601, 7873, 4233, 8989, 12905, 9032, 30316, 9177, 22132, 13322, 18748, 31723, 31024, 23450, 21147, 6796, 1196, 11930, 20126, 20636, 31183, 28819, 569, 14872, 12790, 15979, 9820, 14287, 2575, 211, 25890, 6880, 19565, 10162, 24651, 13107, 23820, 5900, 29898, 29438, 14755, 29591, 13840, 24890, 29223, 11306, 7872, 9697, 32746, 31201, 32620, 21095, 685, 22287, 3397, 4354, 29995, 17070, 17846, 15287, 20244, 26531, 7343, 11920, 12374, 6520, 29143, 20058, 24728, 18081, 20771, 20302, 24335, 29104, 5733, 4713, 15705, 13916, 14501, 20881, 13375, 27776, 5282, 32350, 26186, 10521, 18912, 18900, 28691, 16802, 1973, 5846, 23538, 32648, 21523, 32730, 29713, 15943, 13374, 10570, 8353, 14915, 14994, 13222, 12950, 10928, 12479, 13084, 10920, 17382, 20977, 1601, 5839, 19542, 7284, 3654, 8304, 23240, 670, 20256, 27572, 22825, 23846, 26209, 18672, 21625, 20962, 23680, 230, 4177, 5531, 15481, 31660, 16330, 29199, 13583, 22533, 21348, 6333, 28667, 29677, 11883, 16994, 3057, 19263, 30120, 4862, 5498, 10887, 27901, 9878, 26642, 20099, 21899, 30365, 8501, 18933, 11131, 3629, 26415, 27538, 13614, 12440, 18047, 17053, 8000, 28292, 7650, 16485, 22051, 25317, 9052, 4137, 4768, 5324, 13853, 5099, 5166, 13456, 17407, 24690, 16184, 8547, 6137, 16546, 22561, 27363, 16515, 11214, 30043, 6552, 22185, 6103, 3003, 1103, 26994, 32157, 20179, 9367, 21237, 15459, 19004, 16861, 1434, 8435, 22192, 6507, 10830, 5009, 7130, 5590, 22626, 21107, 23053, 18749, 21953, 9709, 21908, 3767, 24984, 2811, 22829, 29912, 25761, 22728, 18573, 13008, 20047, 28700, 7062, 10407, 21324, 2347, 21623, 25839, 10361, 5978, 27929, 5502, 19246, 91, 6687, 25126, 24347, 25265, 5730, 15603, 12604, 29316, 17666, 16363, 8377, 285, 17909, 26227, 21728, 3811, 24804, 32253, 27433, 16688, 24610, 19191, 22961, 2355, 25864, 20930, 20919, 16691, 27464, 29258, 4317, 830, 31745, 6251, 6877, 2399, 29638, 11375, 12762, 7332, 5667, 25485, 22880, 20818, 17379, 14548, 25932, 23063, 6162, 719, 2053, 13473, 13823, 25495, 22505, 31258, 4828, 5139, 18177, 18173, 32589, 9796, 7169, 26352, 28364, 4838, 3727, 22793, 8788, 8959, 25914, 32103, 16126, 25327, 7708, 16301, 16198, 29122, 22573, 24005, 22730, 27114, 13621, 32476, 5248, 23796, 12631, 1690, 22847, 19166, 18214, 3761, 15049, 1456, 25931, 21900, 13526, 802, 32163, 12575, 11663, 23419, 20657, 11405, 24904, 19516, 12900, 2562, 27661, 25505, 27539, 20412, 16848, 8161, 14983, 13617, 21216, 12647, 26259, 22384, 24026, 23157, 20780, 13603, 3598, 16992, 12391, 31663, 3444, 10221, 22610, 5495, 25246, 1109, 12378, 30361, 28655, 1704, 17395, 11703, 27849, 31031, 2092, 25909, 27083, 2266, 23790, 5353, 11111, 14598, 14551, 11443, 17674, 20271, 8837, 12050, 733, 12645,\n30996, 16169, 6451, 25509, 12173, 14279, 26788, 31561, 17671, 32158, 8843, 14348, 4192, 8812, 26331, 6317, 28446, 20410, 19676, 27174, 18360, 16786, 26286, 29321, 27610, 6237, 22904, 19829, 18648, 7897, 14729, 1351, 22245, 26119, 9617, 25055, 32729, 7808, 9489, 3481, 23795, 14950, 19007, 26452, 17130, 12441, 12171, 12215, 32232, 31128, 24406, 30706, 20164, 3283, 17972, 11970, 17759, 32137, 31674, 6510, 16734, 1346, 5940, 28744, 29952, 28051, 29923, 19352, 13119, 22347, 11279, 31234, 20138, 7960, 12431, 25053, 19391, 5626, 2905, 13451, 15220, 13217, 31181, 28684, 32142, 30632, 31302, 17075, 15929, 7201, 19462, 20404, 14355, 21205, 13315, 7322, 25129, 9692, 8783, 26455, 6994, 28041, 7003, 27708, 4775, 26902, 22224, 32494, 16885, 13477, 9884, 31210, 30611, 28927, 24762, 25334, 402, 31839, 6132, 32327, 4128, 23544, 9103, 11182, 32696, 5539, 4049, 4262, 26551, 22250, 7822, 15976, 12876, 15122, 27154, 29686, 427, 16143, 984, 2499, 14773, 12904, 15972, 23056, 22274, 16079, 31261, 15379, 14162, 15572, 11468, 10502, 26238, 12058, 27683, 23667, 6041, 4151, 26005, 20052, 15173, 14610, 24162, 11778, 4744, 16850, 16493, 12595, 9235, 31164, 19384, 25146, 12687, 2294, 26625, 4938, 10723, 22406, 5008, 28658, 26060, 12984, 24698, 6674, 17851, 2878, 24667, 14836, 20858, 10336, 9039, 4082, 3541, 290, 2190, 27310, 6779, 2956, 25459, 31408, 32210, 11428, 24632, 30232, 6283, 22007, 24760, 6970, 13264, 10962, 14769, 15276, 22089, 8305, 16819, 25166, 3180, 20922, 3043, 32396, 17293, 11818, 23434, 8665, 19548, 9178, 31141, 20693, 17869, 27676, 21160, 9486, 21677, 20632, 31253, 21855, 19927, 23744, 18830, 16102, 14237, 17417, 21736, 25404, 5670, 14792, 22140, 17872, 19139, 14030, 28438, 13040, 89, 3130, 3090, 32637, 32062, 7203, 6711, 21194, 11497, 701, 18905, 9995, 9751, 30785, 31623, 6142, 17924, 15487, 19758, 22612, 8404, 13018, 20197, 5106, 30898, 10768, 6841, 19962, 25512, 2255, 9149, 31762, 31741, 30054, 12841, 19508, 17580, 23607, 31532, 9208, 28524, 17737, 1284, 4697, 31070, 19394, 29841, 19146, 24625, 22143, 23891, 10088, 1269, 11733, 15903, 9186, 10014, 3833, 5120, 13174, 29286, 24949, 16447, 1514, 32564, 25746, 11272, 21748, 22016, 11949, 16161, 29667, 25956, 21874, 10901, 17613, 12794, 27071, 15764, 20698, 13548, 30805, 16903, 5039, 5484, 6312, 31900, 2166, 7174, 21852, 11193, 32463, 178, 27334, 32566, 28993, 19845, 26073, 7225, 19248, 10667, 18020, 4003, 31540, 28649, 8533, 21850, 1169, 22546, 11512, 22564, 16636, 10859, 17127, 2694, 18297, 25538, 12307, 27403, 3172, 2768, 14335, 7206, 27770, 13246, 2123, 7063, 28754, 27069, 8176, 28089, 16875, 11034, 16919, 8269, 13744, 23553, 23559, 7527, 4939, 8678, 10288, 14546, 4971, 9443, 19243, 24363, 7116, 30418, 14742, 5125, 30209, 20364, 14375, 27204, 18381, 9521, 28040, 22087, 14738, 3630, 23102, 2833, 25071, 49, 3661, 28535, 9895, 20330, 25663, 26366, 17572, 17694, 15172, 26800, 30853, 18150, 26164, 22323, 12506, 13596, 25363, 9163, 18712, 28762, 14891, 18280, 29760, 2965, 4212, 11317, 29176, 20562, 30072, 15331, 24811, 31519, 19795, 20610, 10452, 31573, 14687, 2918, 24018, 29365, 9548, 12545, 21387, 14559, 8251, 31707, 12624, 22928, 28184, 18931, 576, 14351, 22417, 12863, 4600, 7852, 24563, 994, 16954, 30633, 17000, 5479, 9904, 18355, 31979, 10500, 5648, 30053, 3900, 9189, 3534, 7306, 2911, 26471, 22780, 11704, 29531, 19070, 6938, 21066, 24101, 32726, 9866, 26644, 32131, 28695, 30094, 26635, 14088, 26524, 10651, 609, 12803, 17201, 28150, 8515, 23747, 11965, 23247, 13841, 6803, 7390, 19788, 30723, 26274, 16532, 6026, 4401, 22367, 25521, 26348, 9844, 1868, 22797, 29043, 23519, 13892, 3399, 3539, 28638, 13415, 18228, 12183, 19977, 1126, 14280, 9469, 10255, 25026, 20836, 23951, 14869, 21627, 17977, 19704, 22624, 8780, 6606, 9732, 7039, 27404, 29685, 19341, 16379, 817, 19177, 16159, 10841, 9430, 7065, 15792, 87, 14046, 23523, 27410, 16098, 17812, 16318, 2339, 27554, 12655, 16427, 12957, 29678, 30424, 5159, 21825, 21250, 27725, 21064, 10237, 16504, 11884, 3867, 22076, 27500, 7951, 25414, 20571, 26311, 25843, 6832, 8053, 18732, 2602, 22776, 6380, 22415, 24856, 16839, 22791, 11030, 21434, 17026, 13743, 27930, 15102, 13786, 28122, 20208, 23013, 26826, 14070, 28852, 10662, 6095, 29642, 31972, 7543, 11809, 23113, 7106, 9901, 2312, 20140, 22733, 26007, 3667, 12278, 16419, 32551, 13153, 11379, 18130, 18350, 19370, 8637, 13424, 9153, 23570, 18788, 29909, 16271, 24860, 11790, 17471, 24977, 29336, 2982, 8566, 16455, 32694, 5669, 17288, 11273, 32547, 254, 22643, 8004, 8747, 27105, 8950, 5928, 16273, 20283, 14577, 12635, 18668, 7867, 12407, 15210, 19452, 20443, 30552, 4163, 12325, 17658, 25692, 9127, 30815, 14207, 15660, 12150, 4945, 31063, 127, 25901, 7501, 13574, 9801, 15462, 7433, 32428, 19715, 1424, 30631, 9262, 29136, 28991, 24883, 18427, 18773, 6971, 7330, 16930, 9833, 27939, 6909, 19907, 18124, 16901, 16177, 32535, 6592, 8583, 16673, 17326, 32242, 19356, 16622, 97, 27473, 3423, 17426, 15437, 3507, 14922, 7889, 3094, 28778, 28322, 4454, 15412, 25637, 1525, 27290, 31044, 15068, 23687, 5443, 15424, 10010, 723, 29434, 10554, 21889, 14203, 29216, 5901, 6155, 23333, 17360, 15111, 16635, 5382, 6616, 11010, 24875, 26810, 16018, 3835, 32517, 20045, 16700, 11835, 15070, 11968, 6455, 27588, 4499, 21992, 31041, 23366, 5880, 2984, 27186, 16562, 16705, 9454, 26128, 4644, 11184, 27852, 30274, 13881, 12467, 27272, 7913, 13908, 30969, 10152, 17494, 16543, 9231, 29557, 31937, 31073, 16428, 10206, 25477, 11766, 25034, 28018, 7848, 21210, 18872, 5789, 19535, 17278, 25462, 13307, 14065, 23576, 15591, 29626, 5254, 26723, 4308, 20168, 21534, 3326, 25626, 32380, 20354, 9520, 29603, 26656, 10464, 349, 14208, 18253, 9558, 27194, 2475, 6740, 21883, 23602, 31838, 18941, 314, 24492, 18694, 32121, 24217, 29752, 18850, 23301, 9340, 19502, 5145, 651, 21903, 18048, 15114, 5361, 21539, 1680, 5607, 14206, 24432, 6757, 2313, 19052, 11411, 16869, 17716, 32466, 6325, 29787, 25866, 29558, 30696, 16383, 15254, 25117, 9890, 9577, 11386, 4263, 5718, 20203, 8384, 19255, 32085, 753, 20258, 16245, 8953, 28673, 2493, 13913, 26953, 18106, 23045, 28568, 13035, 24783, 4528, 18212, 23140, 30401, 21686, 16623, 29452, 29377, 9949, 7414, 10646, 9986, 14909, 16492, 8578, 16199, 22855, 27408, 12321, 9968, 24570, 30662, 27571, 15493, 17425, 22803, 21557, 3732, 29175, 680, 30277, 7615, 28525, 12115, 31059, 26605, 24764, 7542, 24543, 31597, 14973, 10653, 18483, 15059, 4701, 30453, 124, 30225, 10076, 6160, 14916, 12396, 17823, 26316, 26033, 7805, 19456, 21004, 10547, 13745, 32645, 18758, 22707, 3726, 4395, 510, 18632, 7256, 15774, 11880, 14266, 11498, 20589, 21475, 13286, 10346, 9342, 5357, 21065, 11692, 28812, 20501, 9373, 14299, 27970, 21939, 18243, 18739, 10515, 15875, 16516, 21037, 25799, 23122, 8663, 31834, 16593, 1368, 11509, 32641, 13733, 32275, 6921, 3796, 15192, 11877, 25543, 18794, 21428, 10690, 823, 9595, 20637, 1406, 26617, 27173, 16267, 24712, 5171, 28210, 1582, 5500, 27774, 18528, 6751, 15272, 28473, 3416, 19392, 15783, 13761, 23787, 6643, 10549, 3560, 22878, 22013, 8973, 27211, 2147, 30363, 12346, 8712, 31617, 31554, 22820, 9254, 12824, 18119, 11878, 8355, 30826, 11797, 543, 29845, 6, 3174, 15358, 22491, 21391, 13299, 20915, 2709, 19832, 29289, 6943, 17286, 11439, 11050, 3579, 29861, 325, 14005, 10905, 3783, 22634, 9363, 574, 32166, 22376, 15848, 16304, 30508, 23945, 4103, 20655, 7781, 25882, 20310, 1040, 12660, 14912, 9797, 14314, 23841, 22066, 8640, 17496, 21112, 31833, 21145, 21947, 19658, 16533, 32349, 25353, 26329, 116, 21573, 3268, 30117,\n16433, 20035, 23042, 31473, 12761, 8430, 13248, 29828, 16389, 18564, 10864, 16637, 11870, 10185, 3019, 16214, 23979, 251, 19505, 28277, 22569, 25041, 22891, 21192, 12014, 19698, 28079, 9300, 20590, 4241, 10609, 23036, 20357, 1753, 8200, 26075, 8958, 7100, 12842, 14152, 19742, 17229, 29256, 26996, 28808, 11547, 15547, 30481, 17354, 11518, 3368, 17414, 21440, 22292, 19803, 19115, 27563, 11081, 24491, 7695, 1535, 18088, 25861, 22531, 11377, 26676, 2907, 6252, 3099, 20319, 31135, 11436, 7657, 21682, 27528, 28381, 16558, 30136, 15703, 8291, 7612, 27785, 16443, 16957, 10081, 31926, 10246, 9057, 27426, 18402, 3880, 31615, 32298, 6393, 12757, 10182, 13714, 27490, 29291, 25634, 19021, 17078, 19931, 7132, 12766, 28326, 7839, 18071, 29265, 24362, 20933, 5981, 64, 16894, 31643, 14073, 23583, 5437, 13301, 18952, 1980, 30803, 25273, 16287, 31367, 9415, 4491, 18338, 10524, 22842, 17239, 13605, 1155, 16409, 10776, 5222, 2455, 29697, 13355, 22437, 17828, 31539, 19921, 3304, 28554, 18550, 8066, 12830, 17486, 17581, 31777, 12291, 11533, 25792, 14327, 30495, 1119, 32333, 30278, 10354, 8737, 18410, 13932, 17959, 14539, 28285, 22047, 5001, 25163, 23794, 10854, 3842, 22918, 5373, 23515, 8654, 32343, 30107, 28661, 16675, 13033, 27701, 9936, 17058, 2877, 19457, 368, 4243, 17866, 17031, 21961, 16621, 23471, 9281, 295, 30907, 22557, 8043, 24640, 8284, 31837, 7246, 27292, 20068, 22544, 27878, 21357, 31287, 981, 6786, 17101, 19377, 14921, 27517, 6195, 8856, 12533, 10017, 30601, 27891, 12778, 20832, 15227, 4018, 18145, 18391, 1633, 6848, 20346, 12565, 11392, 12449, 17285, 17912, 10693, 450, 22077, 13875, 4656, 30684, 19834, 14226, 31761, 13868, 12585, 5451, 27560, 26172, 27044, 17385, 17512, 9338, 27815, 14513, 30095, 3677, 10110, 19114, 11946, 28777, 16248, 2153, 23432, 1522, 25871, 3206, 721, 1314, 30509, 13781, 27308, 21035, 23270, 9278, 10868, 24964, 17943, 11461, 20669, 9593, 10315, 7378, 5493, 9686, 22679, 3443, 16010, 4110, 1639, 21569, 19823, 26937, 8308, 13433, 28429, 8470, 8588, 17588, 12691, 14866, 26054, 24730, 31019, 23278, 12299, 19500, 15342, 174, 16404, 22589, 4131, 3124, 15261, 12198, 4887, 663, 21944, 11805, 11469, 10775, 5110, 3898, 14240, 15182, 10321, 30332, 11148, 31396, 8123, 8757, 26856, 30477, 12266, 7763, 19222, 13695, 19910, 18301, 21151, 16550, 9191, 10589, 21050, 11795, 19880, 5738, 25787, 7078, 15456, 21491, 11490, 21223, 27346, 18082, 17259, 30158, 31053, 4725, 9706, 12357, 27805, 15586, 19112, 23005, 9128, 5823, 7868, 29670, 15524, 25201, 31312, 20291, 2436, 15637, 22243, 25430, 10448, 16787, 8336, 21609, 26481, 20585, 18310, 29976, 20285, 5497, 933, 14150, 5983, 18206, 4247, 23393, 2977, 15417, 19339, 21747, 9720, 13729, 3041, 24827, 412, 15877, 10128, 1671, 7828, 885, 29940, 15213, 21780, 12838, 11628, 31569, 18408, 24966, 19167, 21431, 22404, 14859, 7447, 18437, 21306, 25405, 19666, 23369, 20861, 21504, 7769, 32175, 4085, 30918, 16548, 24548, 23517, 22993, 11242, 2820, 25300, 22849, 2988, 2051, 6660, 1462, 29120, 28336, 4062, 5394, 10919, 15188, 834, 2802, 2402, 16870, 9264, 25794, 12665, 28416, 1592, 21882, 14963, 5903, 14366, 2596, 24444, 9644, 30241, 32616, 21898, 8791, 3860, 17680, 3556, 10972, 31390, 18139, 32130, 14116, 23294, 16138, 16293, 12988, 25389, 26491, 784, 15599, 15523, 18292, 26338, 2652, 10475, 22824, 32360, 18784, 15576, 11083, 11632, 28166, 29727, 7759, 17528, 9670, 15845, 11475, 17495, 25568, 25278, 12208, 6263, 5658, 13398, 22639, 31823, 22071, 32598, 15708, 19024, 24246, 28960, 738, 32212, 25496, 12591, 21275, 32421, 3471, 22615, 25987, 9209, 10911, 21361, 22859, 14074, 30742, 507, 344, 14390, 28944, 16011, 25274, 9522, 16654, 31801, 1779, 15216, 15550, 11234, 24974, 23334, 13386, 22474, 29249, 27466, 28820, 16456, 25279, 5482, 3211, 19903, 7023, 14509, 10374, 19520, 28561, 18409, 12272, 28567, 8857, 18496, 22201, 1585, 6019, 13019, 21215, 25415, 9675, 28352, 29440, 8622, 15731, 25849, 14128, 19398, 16803, 17748, 17119, 3409, 24360, 15904, 9684, 22006, 5422, 20071, 26957, 18681, 22120, 30713, 9491, 21248, 6466, 21206, 27198, 1656, 26236, 27056, 16178, 5720, 22116, 28605, 15151, 28335, 11426, 806, 23330, 31440, 24151, 22114, 13431, 2272, 28100, 4024, 3911, 18576, 20706, 31879, 5581, 15310, 3901, 7407, 12787, 9215, 12994, 20865, 17848, 16190, 8628, 14774, 12573, 11126, 32002, 30324, 12409, 15054, 9748, 27574, 2753, 13328, 22486, 30311, 17237, 30528, 22920, 32530, 3111, 22379, 1147, 4057, 29770, 13070, 8230, 19371, 16630, 26883, 12016, 9194, 22633, 19360, 21921, 390, 27153, 13127, 4541, 23735, 6967, 18378, 4025, 3958, 23149, 32048, 16980, 14163, 19945, 30260, 29140, 11195, 11967, 8393, 537, 27108, 6569, 11614, 3135, 25305, 14622, 12836, 17627, 21758, 25818, 1976, 8851, 24681, 30170, 22671, 16222, 7050, 2754, 26775, 24673, 26695, 25685, 25384, 32580, 3230, 13797, 7159, 11276, 9553, 30345, 10581, 20935, 3894, 29757, 18196, 20483, 11863, 7052, 7451, 21257, 1194, 10488, 15517, 16326, 14067, 20721, 10311, 14785, 24657, 2996, 15861, 14446, 15239, 10066, 28648, 30987, 31574, 9422, 10975, 23909, 19908, 4386, 32238, 23475, 858, 4525, 32656, 23026, 14885, 15911, 20625, 15823, 17281, 13478, 28656, 17597, 15921, 31646, 6526, 20688, 12540, 11854, 20064, 1619, 19444, 24078, 4695, 28270, 30954, 26138, 22418, 6622, 5208, 16951, 1231, 26307, 17811, 5367, 16855, 5215, 20854, 22230, 18208, 21864, 19000, 31398, 7706, 31713, 16650, 25004, 4152, 7215, 22765, 26219, 20005, 10892, 23300, 3255, 4032, 7282, 26545, 31797, 25938, 30731, 15394, 890, 31132, 31560, 8508, 10870, 7860, 23890, 24030, 12326, 31425, 14263, 11305, 16073, 10113, 12648, 10516, 28279, 16285, 19458, 11104, 28550, 15247, 26213, 10432, 17601, 7502, 1952, 29148, 30884, 11212, 10015, 22981, 21418, 9652, 18186, 31950, 24425, 1165, 24010, 12886, 19675, 15485, 16865, 14934, 20773, 26361, 21393, 19625, 15914, 10359, 16554, 22395, 25536, 14569, 14282, 2840, 22300, 5428, 27512, 23091, 1170, 15803, 29931, 24912, 31888, 19399, 30088, 15119, 17853, 15007, 23257, 6264, 17502, 15381, 17126, 14505, 10586, 11935, 32452, 29017, 16820, 10363, 28319, 9419, 27548, 28739, 19383, 4924, 1871, 16264, 32294, 6290, 15558, 13721, 21744, 11296, 11693, 19875, 2952, 19681, 26064, 23654, 5992, 32408, 7258, 6495, 19119, 11609, 28499, 3120, 18019, 9358, 13349, 3121, 15095, 1402, 5761, 28172, 13308, 16906, 14556, 13701, 26223, 23379, 21127, 6063, 5697, 25113, 7249, 446, 7264, 24813, 21495, 10517, 14745, 32136, 16220, 966, 20372, 1383, 27679, 25064, 10077, 32731, 13859, 13110, 21803, 23228, 31538, 7324, 15996, 11605, 22800, 8311, 15990, 15957, 4936, 26692, 4124, 20689, 3070, 30639, 4035, 18463, 14655, 23907, 4830, 1860, 27238, 23156, 11535, 18695, 16943, 4153, 22744, 18420, 3707, 6579, 15989, 28802, 5811, 19828, 2175, 998, 18478, 6101, 17535, 13637, 30376, 1319, 17106, 27144, 20451, 26741, 12711, 22900, 9713, 19543, 2124, 22594, 7744, 27399, 32402, 4284, 13092, 27608, 28935, 15876, 21636, 381, 12098, 26922, 31924, 20338, 21122, 21722, 11157, 20808, 23052, 16689, 16156, 1389, 13666, 4726, 31911, 10332, 16956, 19125, 27325, 16486, 28600, 14031, 27340, 26505, 31194, 11730, 13909, 8403, 15895, 16124, 21837, 29774, 13021, 6276, 10395, 1079, 30242, 16761, 28616, 10610, 31402, 16987, 12671, 26934, 32398, 17151, 17876, 17238, 20015, 13692, 22481, 2938, 13551, 28881, 11053, 22396, 11190, 23800, 31025, 14308, 10423, 32174, 20447, 20184, 2447, 29870, 7012, 16659, 18426, 10902, 14205, 118, 3614, 14034, 2077, 19174, 22390, 25979, 9771, 15465, 13414, 21269, 14447, 20786, 5082, 9470, 21868, 15235, 21369, 8936,\n1362, 30379, 30781, 16970, 31806, 12092, 23928, 26566, 18066, 30810, 10140, 30811, 8195, 26175, 3208, 24210, 27192, 12680, 9120, 28859, 22158, 12934, 16425, 3563, 3757, 19170, 11496, 18533, 21801, 3510, 19299, 13387, 5461, 11492, 30370, 9757, 1174, 29149, 26680, 23827, 15439, 10831, 18278, 15328, 26233, 866, 4063, 13844, 9046, 9864, 31233, 30045, 20262, 32010, 23090, 30656, 14102, 30791, 17640, 25108, 11394, 12866, 14531, 9873, 10386, 31112, 27010, 9880, 30906, 27163, 16239, 19408, 23958, 29512, 12928, 16606, 28958, 27682, 22017, 31631, 466, 20389, 32193, 18518, 22940, 1493, 9755, 19194, 12347, 14201, 2826, 29259, 1837, 8645, 22265, 23433, 19308, 8945, 26573, 28395, 19395, 12086, 16302, 22450, 5807, 2559, 9026, 9596, 5263, 18844, 18510, 24510, 24757, 4461, 13691, 28157, 10465, 16743, 26884, 21247, 14344, 7484, 22726, 26347, 23657, 1530, 16066, 23328, 8840, 27747, 17679, 19626, 16335, 13166, 6931, 275, 8005, 21406, 32348, 25498, 11340, 17352, 6761, 5862, 2876, 22072, 21126, 15839, 30036, 14892, 28480, 11136, 20385, 23706, 29252, 20206, 17440, 28586, 11216, 18698, 29160, 23755, 11513, 20110, 30484, 25288, 14667, 31647, 15611, 1911, 19081, 3800, 31545, 25946, 4356, 30790, 27411, 8748, 5882, 28445, 11767, 3980, 12343, 23516, 26858, 29195, 30198, 4483, 9350, 11248, 66, 29055, 21851, 3938, 28604, 28034, 14307, 2822, 130, 18229, 12264, 7297, 17734, 21466, 10367, 6428, 31527, 23573, 3456, 311, 4848, 19657, 16415, 461, 15150, 10070, 19432, 17607, 10316, 30420, 26254, 18565, 28501, 8059, 21695, 20332, 12168, 23914, 17256, 23465, 28439, 804, 21172, 18305, 17128, 15496, 31770, 19831, 24269, 15449, 6110, 32475, 18647, 2677, 7141, 25510, 14021, 9237, 15131, 17997, 13539, 20299, 15908, 15809, 9753, 5889, 30985, 4294, 8341, 232, 25186, 16374, 13558, 21432, 13571, 32068, 26636, 8429, 27049, 25953, 9598, 29005, 10871, 30567, 20029, 30944, 336, 21482, 8671, 24529, 11516, 18989, 14330, 7350, 15039, 19767, 4079, 32039, 6610, 14674, 29800, 16904, 7832, 27142, 19143, 2928, 28466, 20137, 2860, 24647, 4607, 30425, 27881, 12684, 4147, 10230, 5599, 6138, 7791, 8285, 10190, 22242, 31323, 6027, 28320, 6926, 12666, 4164, 25632, 5481, 14082, 18428, 1136, 18414, 32438, 18181, 3840, 27910, 8417, 26272, 1795, 20309, 7319, 12895, 19584, 22905, 30447, 13147, 17418, 31205, 26207, 27301, 32254, 26492, 24255, 22368, 23337, 17416, 22055, 12827, 31520, 32615, 12236, 23765, 12881, 28817, 24265, 13972, 31878, 28984, 20572, 20074, 16147, 14900, 14220, 28519, 11517, 12767, 30581, 8767, 21597, 5554, 3014, 32470, 7086, 1370, 25263, 25695, 15302, 26306, 25831, 722, 13229, 15309, 3436, 22059, 18560, 31343, 29287, 29625, 14664, 32344, 13869, 23111, 24112, 31552, 1876, 28896, 24621, 3419, 29085, 25177, 4238, 30408, 26210, 8633, 16403, 10033, 10934, 20891, 12880, 4170, 8861, 23730, 26376, 24212, 20185, 30087, 30042, 4341, 7216, 11649, 3720, 21278, 28186, 23939, 18998, 15667, 2162, 15860, 28737, 13126, 3978, 26121, 18870, 6106, 5654, 28092, 21148, 20496, 3739, 12811, 5272, 22528, 28181, 22096, 32113, 25153, 25595, 32577, 9124, 6178, 25670, 9436, 27972, 13994, 14759, 2132, 11720, 20750, 10305, 18832, 13395, 32187, 17012, 17987, 24714, 6073, 3648, 9828, 5995, 11437, 7415, 9756, 11181, 26563, 31654, 12148, 18970, 11607, 4318, 9725, 13122, 29050, 28841, 25684, 4818, 23138, 21553, 24503, 25330, 26441, 8395, 28688, 2240, 6280, 20500, 13492, 10682, 25207, 15212, 19494, 15400, 14823, 17539, 23595, 15421, 13146, 13673, 23780, 17203, 10063, 20408, 8102, 17513, 28337, 23688, 11013, 20867, 26722, 7647, 15181, 29169, 16046, 25157, 14826, 13078, 27827, 4332, 7519, 17647, 6772, 5528, 22781, 11199, 20982, 24453, 30873, 25889, 24519, 30124, 18814, 9622, 25454, 13624, 19745, 7101, 13873, 12237, 9614, 20647, 4994, 21314, 21574, 13751, 13850, 29273, 11229, 15898, 31959, 11826, 26801, 3213, 15081, 17842, 3137, 10217, 17188, 28549, 1076, 2165, 13319, 10028, 26671, 25523, 16023, 25406, 14953, 31374, 19818, 1859, 1548, 9348, 28982, 15669, 20475, 29955, 11076, 28623, 12973, 7024, 16033, 16751, 16483, 17568, 9021, 12017, 15486, 16246, 17179, 23260, 10156, 8323, 5381, 1317, 11112, 9919, 9899, 19294, 30560, 29449, 26332, 15512, 11706, 9445, 17456, 18959, 18950, 17276, 32449, 2949, 2302, 20965, 5774, 13090, 28295, 19270, 6404, 14495, 12411, 17890, 30029, 1796, 10351, 2573, 14949, 8841, 3167, 22787, 27063, 19830, 12453, 27771, 29422, 22067, 7532, 15946, 5913, 16968, 22866, 13379, 13263, 3906, 5070, 19556, 22236, 8997, 21853, 6454, 23691, 8781, 19783, 4729, 21178, 3622, 16846, 76, 9998, 11313, 13486, 17625, 24614, 22690, 5777, 16407, 24349, 12708, 32705, 14842, 19433, 11683, 21385, 16527, 21719, 20728, 15753, 13755, 17219, 15482, 30419, 12063, 1066, 10995, 6222, 31609, 32241, 23640, 2336, 25086, 14159, 1291, 11123, 14289, 3478, 13220, 21395, 14803, 32426, 8585, 12203, 15139, 10472, 18620, 3512, 6661, 31471, 4817, 19754, 13135, 12428, 8369, 32345, 24427, 29886, 30916, 7021, 21161, 23611, 22739, 20296, 28232, 12114, 15873, 19603, 24882, 9991, 1158, 25271, 7842, 21024, 4878, 7252, 128, 20382, 9830, 17055, 7797, 19971, 2100, 16959, 5563, 20716, 5100, 6176, 9474, 2653, 15880, 22393, 29878, 5252, 13689, 29255, 23903, 28835, 4723, 15917, 30177, 31516, 19354, 2870, 12383, 12475, 18582, 16664, 9612, 12192, 1252, 11074, 1081, 5924, 28138, 22521, 10409, 28431, 19604, 9679, 27507, 26694, 7368, 24128, 30102, 21053, 12620, 11801, 8688, 20453, 14849, 31877, 18914, 17121, 13934, 28829, 18324, 20517, 29397, 9063, 21485, 883, 20109, 22352, 7541, 32450, 26791, 14403, 8543, 21333, 21340, 20407, 4614, 29261, 11847, 4645, 7490, 2009, 26480, 28581, 15587, 24079, 10514, 4910, 11843, 29393, 25471, 29672, 13553, 939, 24752, 13167, 22534, 25921, 8862, 11441, 18568, 20924, 22792, 12030, 16854, 11365, 31133, 14239, 26495, 20375, 13646, 19190, 21142, 11309, 13469, 18527, 9540, 20166, 25351, 27072, 15214, 10579, 5265, 30948, 13448, 16457, 9495, 14372, 20952, 27031, 9897, 5968, 22108, 302, 23371, 26242, 19581, 937, 3500, 10213, 21589, 29769, 14129, 15356, 24489, 16107, 12785, 6179, 21790, 27846, 21499, 23647, 26907, 3694, 28482, 31083, 11440, 31503, 18800, 20118, 7607, 24305, 3030, 26097, 29768, 15931, 23904, 725, 22732, 3632, 32382, 31984, 11454, 30991, 28384, 28422, 16402, 11082, 14743, 27185, 12422, 16961, 3119, 25789, 28917, 26662, 32497, 23440, 3258, 4781, 17521, 27524, 5618, 19296, 25933, 29693, 15438, 3045, 1210, 19062, 19446, 14362, 11398, 3437, 16681, 27414, 19723, 3518, 18728, 11546, 12486, 8975, 20827, 1089, 21703, 22991, 29887, 13190, 13320, 17593, 3185, 9296, 9441, 12505, 5597, 23176, 21831, 17300, 28853, 12123, 27237, 13455, 20970, 30071, 12418, 16766, 3853, 16362, 29442, 9542, 15642, 8811, 23358, 16920, 21186, 32764, 2057, 2159, 1931, 19642, 32431, 10329, 29135, 8698, 5179, 17005, 2102, 18671, 3013, 10553, 30780, 16465, 17154, 9685, 20558, 16877, 30135, 17424, 24706, 19465, 12754, 21734, 1045, 4174, 17449, 634, 11138, 5499, 25062, 22327, 12146, 32273, 32411, 10918, 32075, 13275, 16358, 13902, 30809, 18670, 19239, 8128, 14235, 9816, 13724, 22436, 15817, 25036, 15509, 7656, 6419, 14319, 13987, 25441, 24581, 20966, 22360, 15194, 16556, 23852, 18094, 8603, 13199, 26751, 32280, 18737, 18845, 27354, 10858, 566, 24054, 14839, 29524, 23981, 25203, 26401, 27495, 10427, 2781, 5042, 4997, 18484, 20139, 5925, 13314, 17592, 30205, 7598, 24518, 7755, 1484, 28389, 15773, 14939, 27839, 29139, 30024, 22684, 20361, 11892, 23727, 23999, 31521, 21392, 158, 5527, 24871, 25649, 23200, 4384, 31365, 25522, 23563, 10479, 9802, 720, 7183, 3863, 18242, 23030,\n3927, 17458, 1773, 25966, 16160, 14410, 20127, 16849, 26956, 12067, 21308, 18659, 13435, 25895, 3994, 9054, 12484, 31921, 10626, 17315, 7835, 22805, 10740, 11613, 11143, 31482, 30339, 8019, 21420, 13244, 18783, 10834, 2419, 17963, 19840, 5795, 17838, 16444, 26672, 12399, 19784, 28203, 9362, 18123, 17979, 1138, 27547, 353, 29649, 20845, 3725, 15230, 25553, 27494, 13905, 32732, 9932, 23801, 14093, 19789, 10965, 5813, 4159, 11731, 28555, 30830, 27444, 15109, 30525, 29409, 31670, 9071, 16359, 12523, 20316, 26001, 23269, 20725, 23040, 24421, 11563, 21377, 20207, 29579, 15312, 21581, 28183, 22487, 31010, 20156, 10522, 11102, 26554, 27208, 18572, 15196, 9841, 21045, 4646, 14744, 5742, 22782, 11259, 15899, 10650, 30352, 4895, 25024, 26732, 3246, 29983, 27581, 7212, 24240, 10194, 17609, 15782, 12061, 11315, 17122, 28380, 10149, 15595, 1764, 28093, 14857, 17994, 7795, 24173, 31568, 14182, 28970, 28242, 2606, 18152, 22903, 1793, 3689, 8401, 24187, 9579, 23427, 31601, 25894, 14493, 19716, 4527, 11510, 20792, 22144, 15280, 18836, 6218, 20494, 5434, 11908, 7664, 13032, 2395, 9080, 31422, 4763, 2365, 4269, 15451, 4420, 15270, 26451, 21212, 14747, 15322, 31863, 27781, 11705, 20177, 5562, 28709, 29382, 4873, 24130, 12603, 7743, 2674, 24422, 30358, 13980, 8567, 24589, 36, 22821, 26028, 28302, 24776, 29547, 24108, 13880, 20188, 29487, 25182, 30983, 15353, 22328, 14252, 1809, 26093, 12640, 6911, 11660, 14678, 3427, 4424, 24561, 32703, 17894, 31449, 29036, 12773, 2947, 26980, 13922, 21579, 30334, 32578, 1188, 29342, 1214, 3407, 17810, 32256, 6707, 11848, 29016, 27392, 13351, 31753, 22722, 29427, 22754, 27388, 29129, 21865, 28825, 1488, 32262, 24410, 10862, 18, 8797, 12501, 10486, 17771, 29443, 17654, 1630, 14884, 12369, 30082, 2373, 342, 18293, 5414, 14846, 30553, 22852, 31621, 19282, 20442, 14575, 29606, 8199, 25183, 6859, 22515, 11277, 21998, 22584, 23522, 20086, 8334, 3549, 32668, 24352, 10235, 9075, 1469, 25558, 17344, 27140, 15766, 9769, 27430, 16236, 17791, 32293, 21915, 23835, 31949, 17885, 31230, 4026, 7109, 17772, 21522, 11208, 20651, 10706, 7885, 8441, 25376, 31585, 12522, 9640, 12511, 32647, 28900, 16243, 29225, 32126, 26514, 9987, 13849, 24732, 447, 29881, 21757, 29718, 10602, 20545, 30883, 29145, 13430, 10949, 6750, 16437, 25993, 18399, 3233, 10890, 13677, 25539, 22894, 1324, 17966, 17634, 9202, 20469, 5476, 9557, 25997, 7069, 2000, 10618, 17577, 27551, 13742, 16831, 30108, 7083, 23182, 19852, 10266, 10170, 24644, 1202, 22653, 9672, 17099, 6245, 184, 10649, 19554, 28924, 32202, 8694, 28159, 19330, 652, 11326, 29942, 10814, 6665, 26762, 23351, 18459, 23310, 31166, 12231, 22535, 717, 26572, 28715, 18994, 27699, 3675, 16295, 7359, 2612, 14671, 27187, 26587, 24552, 24522, 30952, 22513, 8870, 21503, 24317, 26396, 26998, 5068, 14311, 1013, 10003, 29066, 26699, 14416, 25577, 15071, 25857, 16726, 14112, 7454, 20690, 6343, 24337, 1757, 17378, 5816, 19038, 28177, 18628, 15882, 8630, 20295, 16660, 13206, 9739, 6628, 14259, 3949, 32143, 18291, 29559, 13075, 24045, 6304, 825, 22778, 1357, 27768, 4801, 13919, 28789, 20619, 32020, 12985, 1693, 6435, 11270, 10881, 15256, 20602, 15570, 26087, 15146, 46, 26374, 1237, 6754, 16720, 18262, 1197, 11095, 5503, 19643, 25819, 2253, 12450, 29471, 8784, 21843, 882, 29514, 15936, 21492, 23591, 1930, 18707, 4283, 18817, 28385, 9154, 23784, 11003, 30310, 9749, 10183, 12602, 16982, 19017, 14588, 22922, 10575, 16240, 26651, 8122, 7497, 13027, 14170, 14876, 25284, 14277, 21117, 4578, 32044, 30595, 16770, 24628, 2049, 20857, 27944, 11610, 6993, 11776, 5003, 22735, 30854, 25623, 12424, 21390, 15277, 1652, 27958, 18263, 2917, 15455, 10025, 11594, 29714, 3042, 10749, 7437, 28413, 25115, 4338, 13422, 8660, 26567, 19231, 29263, 1901, 12459, 30673, 8718, 432, 25801, 11757, 28355, 6917, 7224, 19731, 17782, 19437, 10598, 15902, 17969, 214, 23606, 22498, 9249, 11129, 4296, 21996, 30412, 17303, 11429, 15922, 16276, 30984, 22924, 28372, 25212, 7445, 10124, 26340, 5586, 11250, 7683, 19102, 24264, 22048, 0, 32306, 13227, 14151, 29965, 17090, 676, 22091, 14184, 15306, 14547, 26780, 28538, 5313, 30692, 24742, 12870, 19655, 14388, 25939, 15973, 16165, 9394, 8068, 20322, 23354, 15373, 16146, 19963, 31798, 29778, 25576, 15464, 12386, 17946, 30539, 9628, 29372, 17489, 32711, 4988, 11994, 1815, 21043, 11894, 1688, 15641, 9925, 12696, 27482, 29425, 22965, 2630, 161, 12795, 25493, 14719, 14732, 18451, 18966, 30935, 10645, 13921, 7928, 10707, 22822, 18570, 19108, 25022, 14879, 24000, 19126, 10997, 28258, 3540, 11572, 13563, 1356, 15193, 2052, 9335, 9390, 19487, 28973, 26767, 17917, 31826, 18581, 10261, 28160, 18980, 6578, 22502, 7806, 22558, 22588, 16908, 13827, 17934, 18508, 10227, 23127, 10358, 15105, 27177, 8755, 12918, 21320, 2893, 22480, 14292, 30070, 32054, 6355, 2409, 29578, 28217, 31941, 10903, 28987, 9148, 10222, 13970, 14822, 14765, 14285, 12962, 23029, 19672, 12309, 22499, 11450, 28214, 11285, 16400, 962, 4637, 31850, 8608, 21204, 5982, 16601, 29227, 30417, 9529, 9279, 11668, 6113, 29308, 11553, 10785, 8612, 6793, 2194, 9851, 19965, 9138, 9031, 18645, 10209, 28197, 20837, 32061, 21844, 11993, 14756, 30103, 26036, 13096, 6001, 7367, 15259, 17899, 25927, 32307, 27836, 6903, 22923, 12284, 14703, 1965, 23938, 31443, 31757, 24259, 32312, 15484, 26591, 16332, 16369, 19574, 28748, 34, 17221, 8320, 12221, 10045, 22611, 27068, 29951, 30584, 28362, 22997, 3634, 14607, 9570, 10413, 27724, 15958, 9330, 9169, 10166, 27710, 16915, 19673, 28456, 31213, 21038, 14445, 6265, 16134, 28339, 13655, 26761, 16204, 27946, 18705, 20098, 21519, 22062, 11756, 22252, 26779, 2110, 10718, 12740, 27020, 3638, 9922, 30622, 24481, 16996, 2251, 10568, 6189, 15575, 11090, 19684, 25291, 455, 30230, 15560, 30096, 30654, 15453, 30406, 31429, 23193, 12015, 32220, 30023, 30652, 24368, 30078, 26645, 31395, 27794, 4197, 17198, 10086, 17711, 14300, 2891, 4222, 20515, 7045, 20697, 22819, 32336, 18942, 17033, 15223, 26337, 23349, 2488, 4108, 32015, 13155, 14180, 10885, 13587, 30664, 14853, 31300, 4787, 13157, 9550, 2229, 18016, 7344, 7686, 29078, 12474, 16629, 646, 18289, 7937, 26813, 15548, 7117, 19939, 807, 11571, 28533, 22621, 21073, 157, 12690, 9872, 22084, 23636, 11019, 11366, 17336, 22147, 26383, 15893, 18009, 25164, 32688, 7980, 23883, 15056, 31048, 22497, 16300, 4572, 86, 22970, 19283, 9996, 7800, 15494, 32676, 17443, 8615, 10873, 20257, 11063, 55, 6397, 27631, 6505, 16008, 32164, 24345, 7472, 19265, 15789, 28528, 18379, 26190, 26968, 25795, 28526, 28508, 4185, 15519, 11168, 3373, 16084, 18859, 27070, 5800, 20260, 851, 26168, 12096, 24608, 30733, 14654, 6330, 10104, 23006, 5700, 17892, 23160, 29224, 22306, 8175, 12119, 2320, 25972, 26914, 18248, 12925, 17765, 7735, 31116, 14918, 4190, 10836, 18626, 13560, 10750, 1428, 13736, 9746, 5326, 4462, 15636, 10685, 18276, 18057, 26875, 13005, 12443, 16175, 30540, 6458, 14117, 11301, 405, 24294, 5011, 31264, 8955, 17910, 12724, 28948, 9116, 453, 14584, 18991, 18592, 14586, 2422, 5132, 5229, 15959, 7676, 30192, 6978, 17990, 8790, 16112, 29420, 31275, 24931, 21408, 8864, 22647, 12820, 14621, 8682, 28349, 7899, 22790, 26637, 16570, 5969, 23872, 3142, 27389, 11725, 31484, 7624, 27147, 32405, 19001, 8003, 27102, 12548, 13068, 14092, 32587, 21336, 23521, 13080, 8241, 7854, 23514, 1719, 22303, 28588, 3391, 6232, 19390, 21830, 30755, 29832, 24046, 12397, 11972, 17715, 30956, 296, 8900, 18911, 18772, 20336, 16559, 10916, 18798, 13928, 12302, 4612, 26426, 11664, 27302, 30287, 10664, 5374, 27380, 2201, 9336, 17145, 13445, 25757, 30666, 27401, 12916,\n21235, 14818, 18791, 14641, 24694, 32499, 22914, 20265, 9912, 10958, 6639, 14716, 6469, 4921, 26530, 14254, 8920, 17639, 17645, 15761, 25665, 16328, 23942, 21093, 13271, 23989, 10837, 24785, 16209, 9061, 22441, 24629, 17573, 14572, 31393, 26402, 26697, 11846, 29924, 29589, 27674, 15747, 21007, 10852, 19743, 6042, 10721, 5368, 29666, 8221, 25785, 21529, 16625, 9225, 11912, 29294, 5228, 791, 3048, 5571, 32560, 11914, 16277, 14976, 20650, 15108, 21616, 23578, 1853, 20937, 15735, 6865, 25513, 20241, 14888, 20976, 9027, 9400, 10981, 27030, 16021, 27217, 32740, 1178, 18017, 20535, 13764, 24535, 29315, 20490, 31375, 3768, 29391, 7550, 23759, 26037, 32579, 12400, 2083, 30175, 25845, 14558, 17116, 11661, 7713, 20480, 14380, 22526, 10338, 14441, 10738, 32737, 25769, 22935, 31630, 19122, 13164, 10095, 24976, 21809, 25964, 28950, 18893, 8977, 6891, 20957, 8834, 30823, 24318, 3155, 3491, 757, 30765, 9980, 1253, 19734, 26666, 11353, 10567, 14940, 1645, 31859, 7837, 17361, 18502, 16076, 25515, 24645, 25151, 4242, 7935, 19055, 18723, 8558, 31142, 3308, 32076, 31439, 16306, 21507, 29564, 23972, 26932, 5749, 3883, 32077, 25480, 10355, 1913, 19116, 5690, 1854, 17087, 11130, 11932, 30492, 8279, 9668, 25852, 23575, 25369, 15157, 22799, 22834, 5358, 6866, 881, 31727, 8761, 29124, 5711, 1833, 32058, 14691, 538, 22563, 4926, 22856, 2979, 20702, 13552, 29412, 13295, 11764, 8575, 17522, 16528, 13416, 15730, 6736, 8916, 16484, 27248, 28204, 26802, 27513, 23940, 26328, 3624, 12138, 28394, 7175, 11947, 29707, 27832, 24433, 14105, 13504, 6297, 28968, 16122, 6282, 30650, 29311, 626, 14807, 18480, 28154, 29739, 13625, 7674, 12256, 18045, 28340, 19423, 16092, 19159, 18054, 1505, 8457, 8255, 15691, 12678, 27371, 32433, 4737, 7329, 31304, 4136, 20152, 12569, 15910, 9222, 26698, 30210, 21933, 1983, 26478, 7874, 22681, 2371, 2288, 6573, 17466, 7831, 3836, 24817, 15079, 8647, 2335, 14576, 14002, 29985, 28884, 13408, 9132, 23603, 28998, 1321, 1400, 11616, 25703, 21732, 28577, 11850, 11162, 15293, 19970, 29236, 28495, 30849, 17696, 24475, 4387, 17158, 19594, 31491, 13814, 2760, 23161, 9812, 14339, 18120, 26607, 11135, 16776, 3366, 11603, 7294, 15559, 29892, 5647, 31104, 31118, 2950, 30718, 14650, 6177, 26117, 27099, 20079, 19865, 5141, 19909, 7177, 24049, 8335, 30451, 1526, 17523, 9633, 945, 28889, 12662, 8648, 9750, 3703, 7751, 20815, 19772, 11555, 6207, 13083, 31285, 14685, 9417, 22262, 17333, 31109, 11255, 10249, 13241, 18719, 7222, 17381, 17372, 8489, 10563, 14806, 13072, 4393, 14242, 2618, 11120, 4176, 19608, 19549, 14291, 17265, 30058, 8049, 15337, 18857, 12139, 19730, 20951, 7066, 28858, 10821, 6647, 31613, 22264, 16910, 10739, 19183, 32191, 32204, 17406, 582, 5240, 17412, 13446, 18003, 21099, 9863, 4576, 5294, 3861, 29847, 23900, 14353, 8466, 14236, 7316, 25514, 30874, 26965, 3126, 8163, 6499, 9855, 12768, 25715, 32192, 9744, 11388, 13170, 27040, 31406, 32766, 21162, 24951, 24321, 8618, 27583, 15057, 10571, 15528, 7826, 6765, 31263, 28967, 16781, 16815, 17341, 11702, 2131, 17473, 29269, 21230, 5594, 15106, 23338, 6820, 9584, 12011, 17104, 9603, 28347, 18806, 10671, 6825, 23498, 23080, 24805, 22699, 17636, 25572, 3275, 12345, 27523, 19720, 6488, 20581, 2712, 9882, 19344, 23025, 29279, 7801, 27366, 32393, 31266, 7108, 32290, 23767, 21380, 7850, 22527, 20133, 15428, 5887, 24836, 7988, 26062, 26786, 26577, 17510, 2544, 13630, 18992, 12416, 31357, 15950, 9698, 6745, 31842, 15725, 255, 17294, 27851, 23119, 10784, 27359, 13798, 6788, 19918, 11529, 4115, 10897, 16522, 18702, 13703, 7374, 25887, 4201, 20349, 2981, 5449, 27351, 7649, 25574, 16307, 15740, 32553, 21198, 24568, 28083, 17373, 7816, 9343, 10672, 29150, 5572, 16058, 30722, 29047, 2789, 30152, 12899, 23185, 31189, 11907, 25017, 11338, 28136, 26313, 11356, 11144, 8024, 23652, 25066, 4803, 4846, 26712, 9931, 17467, 27233, 19393, 15942, 5998, 23164, 17971, 20711, 32596, 27316, 20087, 2683, 25862, 17042, 6984, 30323, 23218, 25550, 17704, 21249, 5593, 16195, 7570, 21029, 25985, 24846, 4210, 31619, 23204, 14216, 8617, 8809, 7436, 442, 16185, 5445, 30788, 12815, 13534, 13113, 13268, 29108, 19162, 14475, 14739, 27320, 25704, 23453, 13783, 18171, 11806, 7421, 15327, 18963, 13256, 18505, 21976, 28536, 13133, 17027, 27263, 5902, 13524, 10442, 11308, 13069, 15539, 18491, 14213, 30354, 32698, 21551, 21673, 30020, 18473, 20423, 9022, 26414, 21327, 19053, 15526, 31841, 11016, 25904, 31755, 30186, 9649, 12612, 16547, 32050, 24842, 14595, 13678, 1442, 15283, 24042, 6171, 24426, 16356, 5550, 22469, 28388, 22326, 13306, 27765, 6933, 24458, 3412, 11132, 6024, 2388, 11012, 13343, 26526, 9973, 11302, 28670, 4490, 8816, 19313, 19148, 32672, 29596, 21315, 32667, 25470, 1696, 2308, 23159, 4794, 28202, 14873, 16422, 4829, 12702, 4355, 31058, 4635, 5182, 11996, 23558, 25057, 17383, 16890, 15289, 7149, 8760, 15087, 30576, 30449, 21347, 15668, 20940, 19678, 9630, 23810, 7220, 7754, 18405, 11215, 13304, 10937, 2259, 5620, 19262, 28637, 24262, 15318, 638, 7914, 22253, 10412, 7916, 10229, 16231, 17983, 32330, 16183, 21877, 18256, 15534, 20828, 12966, 2731, 19478, 7984, 29387, 17082, 6528, 8142, 21637, 10793, 4133, 17478, 20119, 8180, 23749, 5043, 24466, 10985, 25762, 19197, 15167, 19471, 15886, 23417, 16127, 18995, 27685, 27515, 13121, 12598, 14028, 29019, 18606, 12207, 4276, 17234, 20431, 15348, 30403, 6641, 7731, 19819, 16385, 21746, 12769, 24947, 10416, 31733, 15607, 32631, 24877, 26506, 30721, 18891, 28071, 6954, 2135, 15295, 10660, 14593, 7888, 5210, 18943, 5328, 13238, 16477, 854, 11039, 10734, 10932, 25528, 18927, 239, 20704, 4992, 12224, 26235, 17729, 14477, 24359, 28005, 14861, 27943, 8777, 23638, 18260, 22124, 12034, 7962, 9887, 1450, 3708, 26627, 24261, 6159, 5400, 15518, 24650, 28003, 16525, 20013, 27953, 31543, 17345, 16988, 2273, 18128, 243, 21187, 14673, 2396, 4899, 27009, 30493, 12498, 19660, 32206, 1313, 399, 16887, 11654, 24711, 29576, 11832, 11853, 22863, 14324, 3051, 29888, 19523, 15001, 8782, 20498, 4911, 14496, 10510, 20445, 10385, 7422, 10262, 13943, 4993, 12917, 3798, 11634, 12141, 25520, 31514, 22756, 6821, 25991, 5133, 11295, 14608, 32437, 22889, 11256, 25733, 22170, 8894, 1521, 22288, 3668, 21141, 7581, 10933, 27226, 16489, 28726, 14796, 26143, 15364, 7476, 6302, 18314, 16817, 18669, 15003, 15274, 13449, 30973, 17279, 31758, 9049, 19739, 31283, 11189, 28907, 29004, 11927, 30822, 12682, 19329, 910, 17175, 8277, 21810, 14192, 19310, 16119, 3685, 17193, 21644, 9506, 28937, 12233, 27545, 17217, 30290, 11307, 22078, 26533, 7286, 17129, 17724, 11, 6609, 6313, 32364, 25918, 20810, 30149, 12491, 17131, 13100, 11851, 17447, 17732, 23763, 23137, 389, 21791, 298, 31962, 4126, 17062, 26582, 20261, 7035, 25906, 11602, 2446, 9607, 17021, 14408, 24325, 26020, 26161, 23648, 6594, 3312, 12512, 13013, 20172, 12111, 23505, 13610, 15934, 24810, 541, 1865, 19003, 8863, 31113, 23874, 30463, 6591, 21782, 4095, 21084, 28785, 9838, 19226, 16075, 26709, 15698, 24465, 20181, 915, 9146, 21638, 2748, 26601, 5239, 25600, 22945, 23957, 29620, 9907, 24437, 19853, 17167, 18369, 9719, 11066, 23819, 12375, 27966, 11713, 14695, 18557, 7037, 17475, 19477, 12185, 12571, 19334, 31920, 19043, 19286, 16998, 11543, 16942, 10280, 24994, 11910,\n7400, 3657, 3825, 29262, 31005, 4408, 11163, 198, 2245, 23593, 25112, 29142, 27228, 1996, 28560, 1794, 31656, 14435, 25825, 31903, 16844, 8940, 18793, 23047, 18239, 972, 10825, 25992, 7392, 16912, 6228, 19802, 23766, 10232, 20588, 10402, 15952, 10922, 20413, 24720, 26693, 5569, 11913, 12608, 21849, 26237, 7113, 9902, 19883, 16312, 26287, 14947, 27997, 1139, 20405, 6728, 5005, 7371, 3270, 27890, 18736, 12045, 9333, 11824, 4518, 14472, 6501, 27862, 15696, 18876, 8052, 1945, 12454, 17865, 3966, 28810, 14760, 8721, 17847, 7798, 9391, 13957, 2758, 32028, 32707, 23189, 21922, 1394, 4972, 15047, 20682, 6289, 8193, 23964, 15617, 19382, 20724, 16790, 15854, 3305, 6230, 14167, 28718, 30569, 29454, 27520, 17626, 16746, 21386, 10085, 2550, 16490, 2909, 14645, 5420, 25277, 22063, 16475, 20897, 22702, 8164, 7449, 10702, 2994, 1195, 29688, 17084, 25494, 9403, 15366, 22596, 23356, 487, 10060, 4448, 26992, 19967, 11239, 28137, 10135, 9465, 23148, 18031, 15341, 7331, 9060, 17542, 20519, 15652, 18055, 7279, 16022, 15769, 18523, 12967, 10519, 17074, 10370, 9513, 25003, 20077, 6882, 31594, 1653, 18987, 28608, 23382, 1566, 28573, 16619, 8458, 12923, 18051, 12576, 16627, 16027, 1130, 23518, 26844, 20630, 10762, 30454, 16571, 9943, 19940, 32512, 29414, 6374, 8662, 6819, 26076, 22273, 3125, 21456, 20886, 8338, 22657, 32071, 20755, 13807, 26147, 14692, 7095, 7553, 17536, 18416, 23991, 23259, 26218, 3395, 15661, 1907, 26973, 26842, 21017, 27249, 26278, 12363, 18099, 24969, 16034, 1946, 14603, 2225, 25911, 20425, 13569, 25398, 5723, 25276, 16213, 20417, 13326, 20201, 26832, 14087, 8219, 6835, 18084, 9620, 23402, 22134, 16592, 16172, 14612, 7053, 22520, 25899, 23919, 7945, 7362, 746, 8951, 26359, 13864, 32123, 20859, 4094, 13259, 29495, 14998, 27429, 2892, 22804, 23949, 31137, 13150, 25755, 32342, 16189, 14209, 25266, 13900, 23770, 3837, 2940, 27522, 22911, 29248, 28769, 2886, 24257, 29076, 28977, 15624, 11900, 18708, 10241, 27688, 783, 8530, 31495, 14297, 12176, 27156, 23203, 21399, 21619, 7593, 9105, 23710, 29648, 18466, 31033, 6805, 17620, 5796, 19488, 17947, 16867, 8147, 28833, 19367, 22470, 29807, 14296, 13769, 16752, 30794, 16596, 8701, 18673, 27423, 14982, 22113, 28088, 17951, 3866, 26964, 23929, 28856, 17394, 14704, 13065, 30199, 9805, 9468, 15074, 14564, 14421, 31270, 4086, 3087, 9528, 20095, 20606, 26243, 7405, 12961, 16965, 31145, 10617, 13352, 30712, 20592, 6032, 20508, 19867, 27001, 4469, 21928, 23598, 22680, 6425, 5410, 15757, 22692, 16928, 24467, 10552, 6293, 10179, 27280, 24857, 1554, 1180, 14632, 25948, 26904, 15286, 29754, 12288, 15339, 18472, 26472, 30139, 9870, 15666, 4893, 3722, 8376, 25925, 31622, 18343, 8389, 24839, 6415, 15796, 6250, 5653, 18552, 28491, 17232, 4114, 8904, 32025, 12277, 14573, 27533, 17319, 19887, 26461, 7424, 12652, 3403, 15504, 5949, 8111, 10803, 28840, 25000, 24744, 10283, 29829, 16207, 19229, 4773, 7361, 15938, 21243, 7317, 21097, 6527, 4579, 26373, 12191, 10665, 15363, 5812, 27521, 3353, 29568, 14834, 28910, 3228, 27686, 5464, 718, 12318, 17504, 13402, 24375, 14544, 18095, 8970, 26620, 15602, 31671, 19118, 23786, 29191, 24400, 6829, 20329, 24266, 18831, 17071, 6927, 14514, 5339, 11314, 14238, 30784, 18521, 10024, 25530, 9151, 19365, 22117, 4608, 16645, 7829, 21319, 5652, 6697, 3350, 8796, 14001, 17655, 16969, 17755, 30777, 9613, 8855, 18062, 12697, 8824, 8462, 17280, 2437, 13378, 7429, 29981, 25174, 20941, 22329, 11170, 14043, 22463, 20180, 14937, 30119, 14123, 10877, 10013, 13780, 22258, 5622, 10043, 27420, 8626, 21795, 25781, 11665, 10716, 13055, 31529, 8037, 23736, 17685, 25896, 32248, 27270, 15545, 14566, 28792, 26686, 24539, 11283, 5866, 27673, 14862, 8382, 20350, 6247, 16268, 26369, 3955, 28727, 20742, 23219, 15852, 22623, 12672, 8817, 10026, 29088, 8158, 31195, 9028, 20541, 19591, 3813, 18917, 12922, 9972, 9791, 16698, 2799, 14740, 23107, 6682, 31852, 11697, 25720, 4339, 22817, 24486, 26749, 782, 29507, 20853, 4558, 19933, 16045, 20457, 32540, 25821, 23764, 26180, 19798, 30389, 7515, 25659, 6386, 26675, 18244, 14401, 21342, 32168, 8858, 25765, 31640, 24418, 31608, 23397, 4861, 19545, 14562, 28044, 7990, 6168, 23665, 30320, 24343, 32243, 23316, 7599, 974, 30434, 13302, 9568, 17817, 19687, 16053, 12057, 29401, 14532, 20464, 26921, 9083, 2412, 24066, 18898, 8473, 6055, 14683, 32226, 12661, 28309, 8391, 32629, 2801, 28929, 13765, 22698, 25860, 8715, 3607, 6175, 4377, 31096, 4554, 1073, 15984, 20006, 17643, 4038, 16907, 1673, 30685, 14583, 7700, 16632, 26825, 8556, 13726, 6186, 6949, 4851, 24004, 25433, 9444, 8836, 711, 22895, 28224, 22960, 15015, 14052, 11679, 17690, 20994, 30055, 10931, 18608, 22665, 11581, 18210, 3139, 19573, 14250, 11098, 22727, 17097, 25982, 19136, 17047, 22807, 14098, 17919, 4557, 1507, 12852, 27167, 1393, 12727, 19430, 26706, 3168, 11549, 12338, 19304, 12182, 9763, 22093, 23882, 6870, 15033, 11164, 3027, 18363, 29978, 25570, 15118, 14165, 15912, 27499, 26815, 24511, 8047, 31123, 13898, 11526, 11534, 22149, 27534, 11152, 22150, 32041, 14064, 11391, 6956, 20112, 14741, 27885, 22879, 23361, 14172, 29562, 18761, 1786, 2563, 8820, 30356, 6604, 30716, 5258, 25220, 25486, 25116, 29056, 11666, 20911, 22079, 17527, 29090, 19088, 5298, 11676, 3620, 9201, 29830, 15892, 31603, 19379, 11772, 8268, 15867, 31278, 19241, 21836, 22507, 30850, 32643, 2221, 3357, 5383, 26225, 15489, 13432, 2204, 14407, 12989, 27113, 21181, 9346, 5729, 25340, 25451, 11799, 14483, 454, 26523, 21767, 19113, 17873, 7825, 8570, 14519, 15187, 9008, 19620, 26745, 31400, 13123, 3679, 20804, 15159, 18013, 1075, 4166, 13420, 6939, 25998, 25054, 15324, 1407, 19876, 2477, 103, 28553, 19700, 20819, 4211, 11823, 23128, 16542, 8170, 2951, 9187, 18889, 23174, 14538, 16772, 7398, 32593, 20757, 8138, 30800, 12583, 25150, 18611, 12897, 3026, 24715, 11018, 21952, 13091, 23585, 8577, 18090, 8076, 6012, 2351, 10335, 17761, 11205, 23621, 21190, 8905, 19333, 2579, 32454, 15166, 23447, 16152, 15267, 16007, 32188, 4700, 7111, 23032, 4400, 26490, 20789, 26631, 23726, 7667, 6781, 9955, 17159, 19935, 27698, 29700, 20367, 22074, 9239, 8412, 11067, 27159, 3129, 13728, 27618, 22010, 31120, 9274, 20748, 10979, 19082, 27258, 5615, 21611, 12568, 11334, 24133, 426, 9331, 16973, 30867, 22870, 10451, 31945, 32554, 10483, 6081, 18037, 14917, 4373, 11779, 6857, 26768, 7013, 3170, 27694, 5103, 14503, 16064, 25103, 24993, 4379, 14637, 31232, 11890, 20841, 5684, 11898, 23473, 12688, 29203, 32468, 2547, 1824, 13789, 3776, 12557, 5223, 10323, 21463, 22196, 25100, 31964, 3387, 9490, 12456, 7427, 8802, 26095, 32357, 17800, 27138, 32156, 21087, 9144, 32455, 20082, 13038, 1217, 13941, 30990, 44, 25712, 3113, 10243, 3779, 32279, 28237, 10084, 18053, 17468, 9883, 2265, 29015, 15982, 6837, 7068, 22809, 5121, 31012, 25077, 11249, 10023, 13508, 1846, 8354, 21789, 24739, 31683, 8028, 12340, 14147, 16967, 31455, 24471, 13042, 6839, 16517, 5534, 8271, 7180, 22373, 31524, 5867, 16364, 7959, 11828, 30880, 14967, 2769, 16410, 18930, 14986, 27886, 22439, 10715, 12311, 3064, 28426, 9993, 18358, 24892, 19453, 13650, 20527, 24575, 678, 26397, 11792, 20730, 32057, 1681, 10034, 17324, 21245, 14125, 18869, 2338, 24048, 19144, 22122, 15354, 9536, 3513, 10058, 12421, 12738, 18415, 30026, 16964, 17874, 6836, 2635, 28363, 23444, 30728, 27166, 22401, 30761, 13085, 7000, 1593, 23716, 4446, 13051, 24933, 31704, 16524, 8467, 32047, 2717, 7996, 14057, 11748, 27028, 27780, 25976, 23134, 19218, 29198, 25035, 4935, 17273, 19040, 18984, 5773, 15222, 134, 22344, 5323, 31634, 13193, 22591, 1569, 16771, 26845, 31987,\n2170, 10675, 6323, 26619, 18272, 15483, 29699, 28376, 6897, 14914, 27952, 27084, 13681, 2701, 24058, 21664, 3301, 14880, 10676, 31076, 24910, 29133, 27103, 185, 2354, 24812, 11448, 6597, 10457, 13183, 17313, 31875, 22468, 15784, 12028, 10833, 320, 31441, 26029, 31417, 15762, 31925, 24415, 20745, 27742, 28883, 18843, 21034, 12970, 23785, 11606, 24280, 26089, 22263, 29798, 11595, 8131, 5763, 6680, 25216, 2210, 14438, 14402, 21969, 12799, 11621, 22477, 28585, 18146, 11871, 17739, 16417, 16707, 26618, 572, 22987, 7431, 17608, 5170, 12814, 26511, 11460, 30164, 5406, 5276, 13181, 27335, 12304, 7919, 22884, 18376, 24832, 28546, 16507, 3008, 19871, 18327, 7890, 30168, 3226, 7291, 32519, 18068, 20639, 5649, 30640, 26733, 22964, 32605, 29729, 494, 4427, 13641, 29103, 17422, 11992, 28842, 7090, 13443, 135, 12362, 30844, 24862, 31139, 28115, 16162, 25803, 30367, 1829, 24895, 28594, 23452, 28174, 24424, 9221, 16695, 4853, 28708, 24663, 5781, 30228, 20092, 26785, 3460, 16514, 4388, 21525, 6200, 12939, 13447, 17931, 16888, 2697, 7036, 16686, 10284, 26829, 5963, 5380, 29215, 21725, 31288, 3794, 21802, 28333, 15401, 16792, 14805, 28391, 13879, 22600, 9494, 6111, 27502, 6322, 9325, 4396, 1636, 10340, 26346, 6062, 3330, 28879, 16684, 7689, 8699, 23464, 12599, 30292, 25908, 15883, 19527, 9484, 18954, 15801, 4589, 28263, 16176, 23403, 25614, 9402, 9759, 12262, 23626, 5095, 31487, 16013, 28601, 10368, 12873, 10037, 27435, 21120, 16151, 20298, 632, 15671, 7002, 20491, 11691, 19872, 31062, 17822, 5818, 29018, 12194, 18044, 5871, 5671, 19266, 8390, 2356, 24897, 22976, 13453, 8599, 20358, 25104, 8179, 14176, 19378, 21743, 13309, 7325, 12001, 2174, 23493, 24322, 29107, 6663, 14160, 22295, 18264, 19942, 5806, 20746, 7595, 24260, 12963, 27019, 29054, 9413, 11038, 17603, 12756, 27377, 13159, 28399, 30896, 25902, 21512, 17738, 25171, 17992, 5207, 22365, 15604, 5285, 3417, 14323, 19902, 16918, 16640, 18309, 5890, 5453, 19541, 1700, 3752, 15336, 26433, 14995, 9717, 12874, 12024, 19983, 16682, 27286, 1027, 514, 20579, 96, 27079, 31775, 16733, 27833, 22556, 18906, 15040, 31081, 5332, 16506, 10620, 12614, 15113, 20617, 29877, 17459, 2540, 20214, 16762, 16985, 11624, 11327, 19079, 24675, 19562, 25489, 23745, 31094, 27963, 27605, 2020, 30482, 11423, 11745, 13757, 26159, 9917, 24494, 24695, 24203, 29773, 10484, 24983, 26183, 29374, 26536, 16801, 3746, 2121, 32584, 15035, 25125, 7715, 26355, 13949, 30602, 32664, 21524, 4017, 15909, 394, 20348, 9997, 5184, 9886, 25336, 24074, 22683, 23534, 30958, 28097, 1239, 633, 6414, 2297, 7702, 20868, 14490, 4109, 20243, 16377, 662, 11194, 20993, 11988, 29212, 30480, 17665, 10292, 28078, 7843, 30593, 18541, 20327, 20039, 9098, 20263, 2342, 14530, 22519, 26652, 7114, 3072, 29441, 9935, 14049, 12887, 6087, 5112, 19069, 7789, 21687, 24190, 20550, 6577, 9038, 10969, 31821, 11501, 29501, 11540, 13283, 10622, 20062, 16140, 28683, 17150, 7402, 29683, 8366, 1125, 10595, 1034, 16442, 23426, 6078, 17353, 19804, 15956, 28979, 6456, 27609, 9356, 9214, 22068, 20503, 27848, 13986, 29210, 16652, 15566, 17220, 30537, 11651, 17025, 8634, 9952, 26494, 13236, 2227, 19777, 6924, 5255, 1958, 16351, 23372, 3957, 25341, 32590, 32756, 6515, 22485, 30325, 22403, 20131, 3431, 6447, 18315, 18447, 24469, 21042, 26106, 9130, 15527, 9999, 4392, 3421, 1963, 15732, 26690, 29779, 5543, 4273, 28331, 20290, 25016, 6324, 30474, 10880, 5146, 15164, 9589, 29722, 19878, 1092, 24043, 6659, 9432, 29025, 13353, 24156, 13894, 17165, 1033, 6912, 27637, 1975, 30270, 14763, 2856, 13498, 28084, 3250, 30341, 10087, 31515, 22239, 1780, 18449, 18591, 12556, 22026, 4885, 19950, 23772, 12388, 6220, 1726, 14328, 4545, 22788, 14094, 18753, 14157, 18797, 27474, 20758, 18218, 28619, 1204, 19415, 13809, 13915, 14596, 22449, 11419, 1557, 28780, 25137, 7778, 9500, 6356, 31975, 25119, 29706, 31381, 20069, 8482, 18113, 12091, 26657, 25741, 9498, 10310, 6383, 231, 13585, 22770, 23062, 17574, 24327, 18928, 12701, 25118, 30122, 17767, 21760, 32583, 21281, 23895, 16017, 26960, 26216, 4178, 22644, 28848, 23776, 5157, 13436, 16323, 15018, 22107, 31110, 27169, 14808, 2301, 16789, 10151, 20063, 30545, 1487, 13292, 2521, 9636, 15191, 31149, 13254, 28371, 27331, 22324, 24631, 12339, 17389, 17565, 13507, 11873, 11029, 7010, 9045, 4963, 22607, 27471, 21332, 21185, 10523, 12801, 5365, 967, 29437, 4475, 20762, 17309, 28030, 10888, 32679, 18039, 518, 22617, 27018, 871, 13495, 28357, 17721, 2588, 19544, 16298, 15750, 20249, 29362, 20025, 1950, 20831, 30588, 9002, 3381, 2522, 30669, 11167, 28675, 29882, 18187, 17628, 21353, 11655, 6937, 20190, 16738, 23633, 2720, 8006, 9966, 8036, 17875, 18429, 2723, 16132, 6986, 23613, 29338, 21639, 32329, 8675, 28523, 2967, 208, 24091, 16381, 13871, 28191, 559, 20539, 15128, 7760, 5360, 15612, 32624, 8601, 12745, 8370, 24200, 19475, 7133, 22141, 3821, 26600, 7112, 22503, 9621, 27803, 1059, 27093, 23437, 28048, 15077, 4277, 9945, 30113, 10277, 5149, 13086, 9510, 32700, 6532, 18436, 27285, 22299, 17453, 29464, 4419, 22478, 27526, 14971, 27274, 20264, 21472, 13470, 15613, 7818, 14592, 9608, 8948, 5644, 4595, 6242, 3313, 4329, 14494, 28628, 21776, 3823, 19188, 17854, 10054, 23014, 8129, 5573, 22354, 10157, 14710, 16311, 18909, 6842, 17663, 3976, 29777, 30866, 17914, 11097, 14271, 5909, 32627, 18877, 15368, 23658, 9645, 28811, 24587, 20111, 28188, 31360, 15051, 16538, 23214, 5755, 19630, 15906, 20151, 4326, 20988, 21773, 7684, 5787, 14630, 20001, 12732, 8869, 14284, 27455, 15027, 12617, 25915, 24775, 27796, 18607, 8203, 28369, 4216, 8847, 5366, 20147, 18387, 25607, 27149, 29254, 27213, 13958, 32189, 26543, 15125, 6205, 24113, 24283, 29997, 22579, 17439, 30610, 9243, 16899, 16841, 29276, 12458, 7073, 17559, 13937, 24334, 15924, 28645, 12461, 4866, 2341, 7653, 8523, 27468, 13277, 32043, 17725, 30571, 3441, 29784, 953, 4765, 26389, 16309, 4633, 22191, 18052, 30423, 11700, 25544, 19775, 32655, 16249, 15763, 26297, 9778, 11115, 23169, 24289, 11737, 11232, 17778, 9000, 14770, 21360, 9165, 32004, 221, 2254, 28265, 8733, 9831, 28215, 3874, 6071, 10596, 31215, 29944, 10105, 18531, 26713, 20129, 7411, 21772, 30981, 12046, 29480, 5951, 1584, 27879, 382, 21232, 26336, 7486, 17534, 27215, 6869, 32446, 30257, 23858, 18311, 4138, 5961, 2177, 10, 28839, 26293, 28598, 21905, 28011, 5238, 31478, 26818, 15316, 21365, 21259, 11722, 21872, 25696, 20160, 4820, 1433, 23587, 7312, 12982, 15461, 25682, 15142, 30939, 16886, 21207, 23431, 17094, 22123, 18813, 27858, 11070, 16814, 27603, 18530, 23003, 26487, 2804, 15473, 4054, 19163, 8542, 29475, 31018, 15897, 12206, 17514, 8725, 29900, 19607, 3907, 8497, 10894, 17039, 17862, 3628, 31892, 22872, 25093, 31650, 6156, 23925, 5114, 25049, 17819, 18542, 30769, 24887, 19780, 18937, 16889, 6830, 18107, 379, 17384, 18556, 13996, 9992, 10759, 14594, 28961, 11346, 18162, 15308, 557, 2966, 22099, 30964, 31340, 4351, 18945, 9677, 20557, 28783, 31719, 26664, 18873, 22479, 7122, 22394, 28330, 11329, 28578, 4957, 12605, 31459, 1922, 6417, 4917, 27132, 7574, 15198, 24718, 2454, 6677, 20247, 8888, 16737, 192, 5933, 16340, 8432, 32477, 6690, 5057, 14627, 9440, 8109, 29961, 11378, 9442, 14132, 29127, 19791, 9206, 23254, 21444, 26330, 3594, 25810, 14121, 15443, 19111, 13003, 15830, 4258, 4863, 20341, 28541, 27461, 15557, 16372, 11005, 844, 7772, 11352, 21648, 17138, 20143, 10851, 19147, 18400, 29624, 7020, 13045, 20231, 8569, 27382, 8878, 29810, 4366, 16529, 16680, 21217, 31303, 31282, 19165, 21103, 18960, 25242, 14225, 5116, 21610, 1923, 32663, 22226, 6945, 9752, 25377, 5305, 6037, 20613,\n20306, 3610, 25390, 10565, 31530, 8921, 31533, 11794, 23389, 8040, 21018, 17978, 20182, 15720, 15029, 699, 27808, 5160, 206, 32066, 16958, 19253, 29998, 30591, 31293, 17386, 22254, 25076, 29925, 11188, 10930, 25309, 32710, 14174, 27121, 3991, 13904, 12639, 10279, 21398, 10669, 8910, 6787, 14431, 668, 32721, 14919, 8015, 16059, 23068, 20094, 17355, 20574, 24852, 19721, 25580, 13380, 3896, 4148, 18070, 11561, 30832, 10225, 15378, 26941, 32504, 25455, 26944, 9896, 13462, 3071, 19345, 5947, 3506, 31848, 13499, 26580, 6545, 26824, 32184, 11841, 20534, 31645, 181, 10592, 1203, 14267, 27284, 21437, 32572, 12329, 5115, 21959, 4631, 20100, 7017, 24236, 3450, 31420, 10196, 28076, 22757, 14215, 31403, 16796, 11933, 19811, 24096, 6658, 16384, 17302, 27201, 25250, 24963, 21997, 5473, 15107, 5552, 14405, 17949, 2207, 2262, 31599, 21470, 28479, 6416, 20712, 2501, 29497, 15409, 24144, 9446, 884, 31976, 16101, 1648, 25439, 919, 27477, 20878, 32467, 7637, 26945, 20030, 15808, 30245, 7269, 28192, 4297, 5504, 23746, 25198, 5060, 16342, 13725, 31973, 29513, 22931, 27790, 23674, 26972, 27379, 26592, 22868, 13105, 4573, 4727, 15728, 23314, 2935, 28800, 7736, 13205, 1318, 2163, 9411, 23645, 13050, 3386, 19134, 23672, 31146, 11433, 18303, 4636, 15064, 14534, 28496, 16989, 6960, 1533, 2866, 8020, 32573, 9881, 8832, 18022, 19063, 32603, 3457, 7642, 10042, 9655, 26703, 17988, 16974, 2672, 15499, 31901, 16421, 9059, 6683, 25869, 9928, 9911, 5582, 20847, 3961, 24558, 16435, 4516, 29469, 9892, 24787, 23135, 13400, 23920, 17920, 21879, 18465, 12913, 4173, 22082, 15251, 6082, 14436, 22325, 11971, 986, 31190, 15694, 3532, 2246, 24024, 21322, 21689, 16230, 18517, 23702, 6742, 10059, 24384, 16863, 11476, 18183, 4087, 14244, 22862, 21427, 7784, 24333, 8259, 26043, 10441, 28104, 25748, 22773, 29550, 30105, 7699, 14367, 11943, 7796, 3337, 15410, 4522, 188, 11646, 24319, 23141, 32724, 30827, 31907, 13968, 30999, 24723, 18637, 11402, 24292, 24076, 17545, 6308, 13768, 10384, 4214, 17516, 22095, 15502, 15086, 7824, 11275, 8531, 26157, 24188, 7610, 5743, 32214, 14135, 29789, 14210, 12062, 7669, 22937, 15083, 9051, 11648, 28851, 26453, 15208, 6022, 4706, 3721, 16375, 11025, 8573, 4040, 24218, 31778, 25371, 12784, 19944, 20510, 9891, 31576, 28824, 2953, 25142, 14045, 27199, 10921, 12544, 32692, 6357, 10376, 17961, 30173, 4325, 28367, 30649, 6587, 9483, 18699, 16044, 1039, 17533, 17297, 7991, 16261, 8413, 10544, 8333, 1938, 30442, 21621, 17240, 8562, 24793, 10643, 19318, 15386, 22060, 15243, 12435, 23813, 16756, 13981, 30586, 17111, 30726, 5524, 4066, 15313, 14933, 358, 30856, 15805, 8794, 24934, 25764, 9657, 4679, 25937, 16197, 26831, 6712, 21603, 11141, 11579, 5460, 1310, 27480, 24894, 8693, 997, 5827, 32152, 3166, 6804, 32520, 26827, 27867, 18946, 51, 14313, 18205, 13231, 29890, 4835, 20916, 16940, 16196, 13656, 30671, 8602, 21167, 13607, 15849, 14133, 13514, 24379, 7293, 3530, 671, 19388, 7119, 7697, 23768, 31525, 29114, 8939, 24457, 6657, 12521, 4070, 25090, 19644, 25694, 23222, 5431, 21273, 19436, 16732, 20782, 13688, 18974, 3711, 16386, 12408, 18919, 28361, 12025, 30751, 8309, 1337, 11357, 20041, 19409, 5260, 15042, 19564, 29799, 12668, 17476, 13134, 22810, 17216, 18365, 6306, 13533, 8521, 6531, 31437, 8849, 13564, 32492, 20174, 6563, 9611, 20956, 4610, 4488, 11065, 20551, 30057, 8893, 20521, 29008, 3827, 26103, 7969, 15699, 8088, 31605, 21863, 12974, 11291, 31464, 6260, 30226, 26933, 26323, 15963, 26335, 27058, 13702, 25994, 8065, 26425, 12968, 30375, 27134, 13393, 10211, 4538, 13839, 21287, 26317, 25010, 11133, 6884, 27795, 21847, 3010, 17091, 15779, 18853, 32733, 19117, 8967, 32173, 17061, 26269, 11729, 7871, 5337, 31236, 24224, 19929, 27655, 30955, 14830, 17697, 26462, 26379, 29862, 16263, 12849, 5609, 17472, 21552, 27598, 6319, 15448, 9659, 19994, 14258, 5063, 23079, 31067, 16253, 13510, 15387, 4368, 13172, 4933, 3797, 26422, 6203, 30630, 14325, 17687, 20996, 8222, 2369, 16269, 21039, 7420, 24036, 24381, 27062, 13390, 30842, 24119, 25260, 9372, 9519, 6596, 32619, 27782, 9437, 14168, 29363, 5155, 17123, 16315, 20616, 8742, 19841, 15046, 11031, 4067, 16728, 10117, 11254, 14056, 1316, 9101, 6437, 17594, 1329, 26257, 14968, 19762, 13951, 4590, 28620, 12992, 4132, 4661, 19633, 21615, 28113, 26102, 28932, 31717, 10123, 24354, 1211, 5954, 18282, 8185, 9068, 30689, 11566, 28831, 24244, 6482, 14100, 11732, 6519, 14459, 10372, 2869, 17618, 7940, 24989, 13771, 21645, 18680, 19972, 17741, 6843, 7006, 9162, 6518, 22934, 28310, 8319, 5605, 20843, 10436, 19996, 13690, 11374, 6432, 13706, 8557, 3504, 28781, 27668, 15228, 9353, 6217, 18167, 30421, 30767, 10421, 14954, 24025, 7425, 25460, 10546, 7370, 11865, 24697, 3562, 2931, 30518, 30172, 16694, 15158, 5828, 849, 13103, 2714, 10582, 929, 2359, 28838, 13782, 23477, 14831, 24431, 9618, 17826, 8607, 17363, 4349, 8873, 10339, 17023, 4328, 6318, 10320, 9664, 18851, 21236, 4135, 24840, 23142, 6670, 13522, 21662, 3404, 27916, 20947, 24562, 19507, 17083, 226, 10661, 3997, 16153, 32377, 28551, 16823, 6590, 15859, 9631, 12689, 3314, 3311, 2937, 19526, 6301, 13412, 13962, 9141, 17678, 19577, 28132, 13838, 6256, 31504, 6959, 11202, 10786, 26843, 29283, 1420, 26923, 9007, 24600, 11139, 21116, 2863, 32458, 27555, 15887, 14326, 10611, 8680, 24206, 8101, 14527, 12507, 4089, 32763, 5415, 26889, 2864, 13842, 26171, 23502, 30529, 30214, 6284, 2640, 25187, 2795, 6749, 31807, 8449, 31819, 29740, 27659, 20352, 31977, 23362, 6930, 14748, 20435, 23677, 15710, 6568, 6044, 3975, 21775, 27469, 23167, 13989, 18059, 3040, 13087, 5023, 23223, 8031, 2060, 19709, 5377, 3803, 12921, 20950, 9041, 15168, 15608, 19998, 32351, 32742, 25738, 14089, 12774, 17965, 18923, 24131, 23551, 29950, 13732, 31865, 13014, 25102, 17787, 14813, 11589, 22721, 2930, 4244, 4303, 16341, 29694, 26766, 24542, 27385, 9433, 14083, 31370, 11782, 21041, 18063, 24571, 13411, 29854, 16648, 29461, 12510, 2854, 22587, 13046, 2106, 22031, 15186, 18329, 14305, 385, 11739, 28434, 6613, 22840, 30720, 17993, 31754, 28264, 18252, 11786, 22212, 4076, 9877, 9082, 11505, 19613, 13956, 5641, 21739, 5576, 14653, 29811, 13982, 27255, 3452, 23286, 11744, 24879, 32575, 22260, 12330, 28462, 17433, 19235, 20890, 21993, 22053, 17080, 5908, 8912, 21657, 1801, 10757, 1058, 4894, 21253, 20075, 32186, 15170, 4598, 16205, 6973, 17676, 27638, 8151, 12124, 3786, 25884, 8711, 13515, 16420, 32482, 25501, 28000, 7098, 19020, 26794, 24454, 20324, 11054, 25068, 17066, 3499, 3645, 27278, 27112, 18615, 26730, 12469, 21022, 7124, 2558, 23069, 2027, 1299, 24490, 25650, 11688, 5878, 30934, 22651, 7812, 12783, 3807, 14580, 11361, 26581, 20434, 30340, 16508, 30580, 956, 30313, 2157, 20529, 32582, 21958, 683, 13995, 8248, 1631, 19920, 11769, 29121, 6420, 32613, 24137, 32390, 1767, 5575, 20331, 5040, 25673, 32614, 9811, 26239, 17048, 8664, 4748, 7461, 12177, 22652, 29850, 30840, 23723, 32098, 1489, 26855, 32410, 4634, 27996, 23462, 32557, 19580, 12145, 21461, 30848, 19041, 14591, 7678, 13778, 16414, 29745, 3931, 10624, 5188, 9544, 32287, 24102, 20533, 8882, 31639, 29613, 29695, 18741, 19653, 4859, 18265, 4875, 2705, 29522, 9857, 16779, 2679, 26837, 16426, 30533, 5747, 28579, 31531, 13974, 14448, 16931, 29853, 26198, 8659, 19766, 31651, 11958, 4481, 30936, 1242, 12607, 13247, 11028, 13734, 27025, 16468, 25606, 2212, 28059, 9100, 9937, 17100, 8829, 7153, 26228, 16130, 1455, 8635, 12770, 28032, 18487, 3358, 9591, 19862, 31054, 8770, 13890, 23884, 18940, 6585, 11213, 31032, 31179, 31535, 18515, 31480, 6656, 18619, 19257, 10743, 2881, 2721, 22953, 9626,\n12846, 10455, 21808, 17009, 23217, 16284, 6273, 27835, 2899, 21335, 16780, 30092, 3133, 32217, 9334, 12246, 16905, 6634, 27907, 25534, 13556, 24498, 32394, 21258, 23885, 9287, 4002, 6107, 23866, 18722, 31953, 16578, 428, 27081, 3972, 11819, 12720, 3349, 12781, 6958, 17891, 32150, 8022, 19204, 9681, 21631, 9533, 2921, 4582, 27498, 21227, 31252, 21570, 7920, 16035, 24908, 3086, 12898, 16740, 13815, 18165, 11582, 8350, 21450, 2633, 6309, 20198, 20317, 23476, 13023, 16440, 15926, 16646, 25396, 31046, 13457, 1613, 1994, 24580, 24175, 29031, 29939, 28644, 9112, 12023, 15664, 32127, 13595, 801, 4180, 1256, 28611, 28201, 10257, 11233, 16104, 31022, 6468, 25935, 32032, 17190, 26410, 8461, 324, 25255, 20946, 15265, 14298, 15224, 22179, 29808, 12980, 17176, 29566, 2629, 12125, 15422, 31884, 14134, 11438, 30861, 9788, 30462, 5921, 2743, 18159, 23567, 17069, 30084, 19048, 21297, 5666, 21372, 601, 32288, 5087, 4175, 2498, 32518, 22694, 15359, 22458, 11817, 30224, 26382, 20883, 17579, 21062, 19013, 14200, 29851, 15066, 11390, 29905, 22244, 8299, 16945, 23596, 12047, 7525, 25365, 19578, 5026, 10107, 30915, 5510, 15530, 14877, 18559, 12553, 16254, 32070, 28282, 28860, 22447, 23341, 21422, 25045, 21401, 19706, 17980, 23478, 6806, 6496, 27772, 18612, 2298, 14440, 9674, 27484, 23527, 21114, 9167, 12026, 24649, 1955, 13396, 12216, 9889, 18336, 29971, 16480, 17712, 17681, 16194, 15836, 18553, 15294, 13191, 8126, 7261, 7779, 21460, 29298, 32666, 2127, 8183, 92, 2841, 17808, 31229, 22747, 32027, 13333, 24194, 9015, 22989, 22205, 16077, 18021, 29622, 20276, 11586, 13955, 7353, 3851, 29872, 27347, 11316, 6940, 15542, 8565, 7703, 27445, 11407, 28038, 29653, 17661, 6934, 24960, 18506, 30870, 28025, 24544, 11678, 15176, 24184, 16294, 11297, 28359, 30708, 30919, 18356, 9688, 27578, 26609, 16399, 10656, 10689, 25559, 7921, 22706, 27856, 12117, 6529, 31462, 30269, 21749, 3601, 12667, 15389, 30405, 17268, 27584, 21811, 10424, 14054, 26660, 29381, 29555, 24886, 13846, 7110, 2036, 1236, 17648, 15048, 28898, 7474, 3492, 12162, 6244, 13825, 30943, 4374, 20439, 18202, 8278, 27713, 6069, 23974, 30521, 14724, 30993, 15052, 22275, 22932, 13481, 2584, 16597, 13480, 2903, 15236, 11117, 23252, 16113, 17944, 4459, 12719, 21458, 7565, 9663, 30329, 17941, 20707, 820, 21897, 20000, 7597, 15395, 20694, 9240, 19045, 10019, 18097, 32638, 642, 20627, 27422, 6537, 10694, 16299, 10009, 25332, 29918, 15490, 12642, 28784, 2333, 8145, 21654, 10636, 12816, 6627, 28171, 20505, 13664, 29871, 31788, 5308, 9158, 30541, 29455, 22314, 6235, 10031, 7340, 30388, 8986, 20923, 15686, 13792, 25473, 25124, 31562, 22890, 11690, 7369, 26344, 30818, 816, 5163, 19328, 25394, 22320, 2041, 31256, 23769, 2260, 26416, 10818, 7386, 12107, 18488, 22649, 25114, 31665, 15103, 30620, 20176, 24708, 18599, 13501, 17706, 18734, 6574, 375, 25281, 24957, 21646, 30319, 32419, 10011, 16822, 6023, 25245, 7927, 21195, 20678, 28996, 10121, 26476, 23520, 7608, 13054, 4622, 25556, 30707, 7753, 10629, 18692, 15278, 8619, 1668, 24916, 15320, 32548, 10846, 19504, 18951, 17020, 30202, 8021, 18766, 12323, 5439, 6898, 7552, 20312, 11862, 5632, 19915, 19311, 7827, 17050, 14920, 15643, 30448, 6521, 9615, 14425, 15831, 10754, 10956, 10055, 24306, 18375, 3662, 30090, 22462, 12235, 29128, 8226, 29402, 14669, 32635, 11956, 20400, 28707, 27818, 10065, 21730, 14041, 30006, 31828, 19152, 18693, 29573, 17144, 30350, 15799, 28698, 29325, 10942, 26782, 25952, 11467, 18279, 23074, 25664, 5430, 20301, 28260, 22510, 31595, 3956, 30920, 19100, 6503, 25268, 15658, 26513, 15153, 1972, 2067, 9308, 11751, 13550, 16350, 8261, 14354, 27612, 20898, 13214, 31452, 25256, 2901, 19057, 9654, 14646, 10725, 28931, 2724, 15569, 12944, 20376, 18312, 20553, 32533, 26136, 8118, 18996, 30386, 1625, 4280, 14424, 17248, 8328, 22281, 27932, 9224, 19674, 13523, 21951, 9288, 20708, 31315, 31824, 14264, 7092, 12694, 1144, 25973, 12282, 30938, 8379, 15078, 31933, 7503, 16607, 13747, 4102, 32755, 11642, 1777, 3933, 32418, 24132, 29138, 11269, 14910, 15795, 20885, 6268, 13483, 8604, 2523, 9879, 9767, 24157, 17434, 28513, 8710, 11615, 10822, 6105, 21079, 29605, 11556, 26229, 12007, 8133, 31091, 26812, 8071, 32487, 27869, 10267, 32104, 19106, 20396, 15240, 23187, 9418, 24725, 4797, 1365, 4837, 26689, 24034, 22759, 761, 19123, 25604, 28021, 16879, 13195, 17092, 19192, 17306, 26252, 28965, 18757, 11963, 18195, 22552, 17816, 13376, 6229, 23666, 6481, 1682, 16949, 5012, 7323, 13010, 15367, 8504, 18679, 24165, 12977, 5579, 22121, 17798, 21502, 1579, 18820, 30369, 9326, 29111, 22493, 25294, 11480, 22008, 10175, 19051, 24830, 30614, 19515, 24153, 27709, 7520, 24945, 32542, 3604, 21412, 23555, 13598, 32510, 3809, 4156, 4551, 12313, 25447, 26384, 20928, 2256, 16494, 14782, 18778, 17932, 25097, 27193, 25373, 26719, 7259, 17824, 32636, 18476, 2184, 29927, 25237, 17797, 31939, 21088, 23975, 31686, 29230, 22438, 2450, 9377, 4889, 16749, 30863, 19325, 11710, 19091, 27223, 1375, 4093, 27387, 16663, 31222, 30483, 25401, 8995, 29204, 21777, 28902, 15231, 31864, 18532, 20512, 28366, 2202, 28760, 23830, 10735, 27048, 29822, 9950, 17224, 2531, 15630, 32301, 1934, 31813, 30196, 32107, 24803, 5689, 27054, 20455, 22357, 12090, 12127, 16418, 21307, 1007, 19656, 1177, 25654, 24029, 23374, 27985, 131, 14711, 22654, 30118, 14393, 1251, 21537, 14649, 6320, 17359, 23976, 15695, 4196, 6874, 860, 11765, 11775, 17833, 10686, 17702, 18676, 14946, 780, 5962, 352, 316, 4016, 16164, 29040, 25847, 19651, 23060, 32722, 24829, 20144, 15988, 23562, 17789, 15317, 2592, 9309, 2349, 15716, 20713, 23261, 10318, 11699, 31084, 5976, 15819, 15832, 13821, 21481, 24094, 18824, 2740, 29470, 22210, 15340, 14929, 3891, 20876, 29039, 13644, 5768, 8744, 7505, 4995, 29897, 30187, 12555, 27133, 26854, 18855, 15362, 16005, 22285, 16297, 2241, 11147, 12462, 30330, 19208, 4021, 14340, 10988, 2655, 20863, 13274, 23198, 870, 4722, 6351, 19509, 21304, 3286, 14689, 18131, 3224, 10247, 6593, 15045, 13097, 17703, 20692, 22164, 18691, 11803, 82, 10487, 21176, 19083, 14529, 30626, 5378, 728, 1561, 16054, 28090, 20776, 22001, 24116, 32073, 5855, 5297, 26598, 19482, 19366, 3926, 26604, 30438, 27784, 3844, 24239, 14010, 16551, 23466, 25728, 10562, 31855, 18780, 14850, 18501, 25492, 31629, 20605, 12013, 18547, 1044, 14480, 22388, 31412, 10616, 13423, 10501, 28024, 22180, 17750, 32738, 30001, 4161, 30409, 19799, 26187, 25337, 17079, 6948, 16568, 3262, 5322, 24456, 19627, 3261, 21240, 24279, 11264, 31549, 27501, 23550, 27889, 15019, 30229, 20679, 27978, 30347, 15345, 30059, 10927, 12854, 19028, 27061, 8926, 877, 13111, 10375, 25002, 14084, 10491, 4844, 10561, 27417, 26659, 6581, 16950, 19213, 18910, 25466, 5922, 23788, 22011, 5280, 15435, 6144, 965, 29499, 29858, 21506, 16784, 32514, 14553, 32528, 32069, 26550, 18287, 16813, 28370, 14977, 27190, 6401, 8814, 28677, 17985, 10936, 15136, 6031, 31831, 24440, 20821, 4495, 20670, 17142, 24095, 21542, 30668, 29219, 22308, 14827, 29719, 24997, 8750, 12632, 30753, 31319, 22909, 29208, 6233, 5514, 23715, 26438, 4097, 20525, 11820, 22461, 31502, 29711, 27989, 22864, 13756, 12942, 8697, 15058, 31735, 4203, 27541, 23191, 23741, 21214, 9915, 28911, 27876, 17292, 32322, 24414, 27735, 24605, 23923, 20744, 3646, 11253, 918, 27847, 21925, 9173, 19638, 17878, 14415, 28257, 26305, 29749, 22524, 14735, 31431, 10473, 5486, 29842, 22554, 7911, 28679, 32521, 15649, 29680, 8676, 20683, 24639, 21233, 30734, 26009, 31075, 15178, 7941, 3683, 10499, 25109, 4778, 17171, 18211, 10865, 26871, 18861, 10590, 1995, 19868, 32640, 4357, 23937, 3442,\n27241, 27336, 27360, 9369, 13427, 18269, 29058, 14, 4684, 25975, 32112, 31051, 28293, 8642, 9825, 25381, 5496, 31501, 24702, 5873, 15067, 16946, 1446, 2283, 28939, 14847, 24377, 23508, 13494, 30801, 23912, 20961, 4890, 16014, 30267, 17733, 7579, 16347, 7569, 6706, 12163, 24749, 122, 32051, 13015, 13267, 28212, 13325, 12142, 7134, 16521, 12401, 11623, 28662, 7173, 14810, 12427, 18731, 31726, 22097, 17332, 16173, 4891, 13651, 8555, 8980, 7144, 30075, 3672, 1545, 5691, 17991, 6124, 17503, 5849, 25037, 18957, 29728, 9559, 20051, 1247, 11727, 23905, 5301, 15810, 13594, 19348, 7617, 23628, 7819, 32132, 32358, 8830, 13878, 11671, 13832, 31136, 21765, 18765, 29730, 10091, 25009, 13242, 25029, 15538, 12730, 25868, 25968, 32524, 13750, 21071, 18999, 2315, 15335, 27843, 21514, 13276, 5183, 15096, 20205, 25467, 11545, 12563, 18834, 8014, 28303, 5013, 17275, 17305, 8639, 18290, 18348, 27945, 18881, 16228, 21443, 3945, 15288, 31769, 12457, 20866, 25877, 31577, 27419, 13459, 13136, 25038, 22789, 9776, 13298, 20477, 26522, 21193, 5379, 11113, 17231, 2913, 24903, 6783, 29032, 15742, 17630, 22982, 23463, 14549, 31410, 9939, 5483, 30992, 1873, 18122, 25657, 29922, 14154, 4369, 69, 29014, 18474, 28711, 6035, 28994, 12094, 27344, 3177, 1395, 31870, 32286, 16871, 9906, 25270, 13615, 14392, 19710, 19617, 21550, 17667, 30953, 17566, 16599, 11226, 9715, 13593, 13468, 30154, 9689, 31072, 8915, 12381, 11287, 7170, 9256, 19301, 9117, 16086, 9171, 27047, 29116, 22548, 13634, 24527, 8306, 15115, 23265, 163, 1691, 17675, 16047, 29002, 8282, 25229, 23467, 10231, 21355, 11669, 6295, 16037, 11312, 31507, 10898, 15025, 30364, 31165, 14079, 5892, 8127, 14540, 15655, 21264, 7557, 28435, 11459, 21711, 22221, 32267, 3522, 18435, 32651, 25646, 19928, 25564, 6542, 16168, 19401, 11151, 26390, 21799, 17956, 15403, 21527, 6668, 24929, 3424, 28189, 27872, 322, 11078, 10403, 9516, 18246, 11481, 15237, 32622, 17635, 6185, 31794, 6992, 14516, 16768, 17134, 15650, 32295, 21964, 11341, 1292, 14725, 20668, 32480, 13668, 27240, 23394, 16572, 15584, 20507, 14778, 12875, 4300, 4225, 11519, 21325, 15878, 29073, 30908, 27532, 8238, 914, 8169, 22603, 5407, 29594, 14217, 8085, 22020, 14928, 31922, 25886, 8455, 27817, 23712, 21698, 24031, 3105, 16530, 13329, 19450, 29884, 8600, 31056, 22506, 30146, 11966, 5674, 22128, 25719, 11166, 5290, 29771, 28378, 6448, 29520, 9305, 3498, 14930, 31534, 11260, 28894, 16155, 25578, 7423, 20902, 7539, 5244, 12867, 22565, 4456, 25635, 18041, 13025, 16560, 9317, 3769, 9571, 11869, 346, 8587, 4036, 11726, 26475, 23395, 16644, 27313, 8866, 614, 20286, 21208, 25217, 28682, 17393, 7289, 20918, 15245, 16394, 22112, 21199, 12327, 8132, 6123, 27476, 31751, 19185, 9946, 28529, 10771, 13831, 9111, 15525, 20699, 7230, 31624, 26470, 10839, 27801, 4129, 6353, 10137, 31780, 21328, 27235, 16247, 25753, 30429, 8735, 5886, 10362, 17701, 8408, 11180, 27184, 21489, 3189, 19474, 21886, 29009, 29848, 2713, 2632, 12210, 27450, 14142, 25239, 23132, 27586, 10239, 6004, 5696, 17849, 22343, 17409, 15215, 8527, 28530, 5919, 13822, 21128, 17163, 3882, 26808, 15582, 15562, 18897, 24823, 22126, 2925, 16322, 7648, 11332, 17550, 19034, 15148, 24378, 8495, 20603, 19036, 23232, 27374, 2070, 16355, 9683, 27315, 26557, 13848, 13944, 10327, 30879, 2203, 18161, 26258, 843, 16223, 2853, 22761, 5634, 5989, 24849, 28909, 16495, 16252, 25916, 3688, 13129, 28014, 12131, 24967, 7181, 30520, 836, 30281, 6671, 22627, 923, 8646, 20743, 8623, 14975, 21966, 21990, 10729, 20235, 25235, 14952, 14913, 20691, 26458, 13654, 12160, 27575, 7412, 3474, 25105, 15571, 25319, 24784, 20096, 7379, 13405, 29257, 23124, 7027, 27695, 4877, 25221, 12932, 16408, 8264, 10012, 11235, 12894, 16501, 29945, 30550, 15269, 13601, 10541, 16181, 8674, 8406, 12597, 31154, 8992, 23546, 32685, 9786, 12530, 14707, 714, 11024, 27597, 6913, 14202, 30757, 22836, 26399, 2442, 18969, 6807, 6373, 23944, 9908, 21902, 7466, 8460, 5167, 23497, 15840, 32397, 4571, 1812, 19833, 10526, 9572, 20028, 26004, 31216, 6009, 31089, 16108, 12996, 10914, 7931, 19101, 12379, 13058, 20814, 1262, 19995, 16753, 19702, 26756, 6174, 14715, 16639, 4264, 24193, 10767, 31550, 19429, 31657, 18092, 10705, 5657, 2108, 26626, 28116, 25145, 5390, 19953, 9455, 3473, 16026, 24759, 10497, 21842, 24755, 13897, 4274, 18235, 9323, 4323, 21423, 22811, 4187, 21712, 22995, 32444, 27365, 25247, 6584, 31946, 3448, 1686, 21608, 1948, 30947, 13439, 13317, 2644, 6310, 9327, 29355, 25101, 22767, 27332, 25788, 5856, 7982, 28651, 6399, 6457, 8063, 9096, 16488, 2879, 7127, 15614, 21272, 11416, 22459, 526, 13204, 24918, 23886, 20004, 9978, 24374, 28714, 20882, 14665, 19847, 27960, 11263, 23489, 29044, 14896, 21975, 3158, 2587, 293, 15889, 21904, 14542, 32432, 18219, 14647, 27304, 12524, 16392, 10345, 14618, 24164, 2103, 27052, 31349, 15619, 449, 28964, 17113, 21983, 22529, 32626, 12884, 30436, 18932, 8165, 9406, 8598, 17340, 18247, 24866, 24304, 4068, 21473, 13791, 11349, 31558, 7123, 16510, 28901, 22374, 11321, 19417, 31238, 4411, 10254, 20793, 17986, 18743, 24851, 30504, 26277, 12463, 4506, 10132, 11225, 18522, 376, 25859, 1050, 24532, 21740, 5197, 247, 14382, 3877, 15541, 29827, 10964, 12633, 4398, 23227, 22674, 28514, 22500, 14652, 28971, 18438, 30296, 23055, 10658, 5953, 12213, 5843, 16063, 18926, 21854, 7786, 18690, 6810, 21731, 12214, 32701, 11294, 25469, 31792, 14085, 26535, 6980, 4647, 22950, 22672, 16643, 18134, 22873, 20419, 3025, 25777, 18549, 5650, 143, 14908, 19060, 31182, 26324, 777, 7621, 26629, 17017, 20374, 10218, 9179, 7944, 5148, 10101, 14037, 11474, 12502, 26510, 29635, 12577, 5391, 3016, 19276, 27720, 9397, 26668, 29351, 30621, 1426, 932, 10924, 9137, 12520, 5435, 6315, 15785, 19824, 9093, 10444, 7265, 6169, 3531, 21494, 13537, 13942, 15646, 23208, 21056, 22453, 31736, 6412, 31472, 14757, 5250, 7583, 14679, 24284, 16718, 18635, 27125, 3438, 23897, 17562, 23446, 29885, 24152, 12301, 8704, 5283, 12305, 17543, 15244, 7729, 5515, 5804, 30647, 16401, 30986, 7851, 17211, 11318, 16618, 24550, 5468, 29000, 19179, 1822, 26388, 15388, 19598, 23129, 3115, 9761, 6758, 17483, 13354, 29948, 7792, 13088, 19680, 31251, 10027, 9926, 9842, 10169, 30635, 971, 22517, 12371, 21716, 31186, 24807, 8554, 1275, 13582, 3605, 10007, 14075, 18005, 23413, 27546, 30574, 11335, 16144, 4535, 29679, 25826, 5916, 26860, 10200, 18160, 13813, 21110, 18176, 17850, 23126, 11172, 4034, 31372, 25080, 18489, 29785, 31680, 17308, 19250, 32289, 26952, 10811, 30683, 15700, 2939, 21417, 11791, 7082, 1198, 10533, 20942, 8227, 22169, 7841, 21833, 3858, 25368, 31808, 13606, 30393, 8229, 26002, 8136, 31771, 10429, 14204, 28697, 24693, 16774, 22874, 21152, 1060, 3758, 27236, 15260, 19272, 30737, 30312, 19342, 7126, 7337, 26688, 18685, 16324, 28874, 19332, 26744, 7217, 6544, 30056, 155, 15554, 7517, 28756, 11330, 9205, 21359, 15476, 10535, 12417, 20756, 9182, 5455, 18116, 5369, 21870, 19201, 7084, 26628, 10954, 3774, 20292, 9055, 3245, 23469, 4256, 1309, 23220, 30346, 24659, 13413, 15977, 708, 25154, 24476, 430, 2525, 26894, 20115, 1906, 24737, 7732, 896, 21669, 5492, 27908, 19506, 20351, 30272, 12676, 9066, 4947, 16388, 14071, 24111, 24930, 21679, 14837, 30532, 13684, 11359, 20370, 27463, 31961, 18768, 13118, 26205, 32567, 15715, 2367, 12650, 26077, 7305, 4320, 32096, 26142, 12987, 16043, 6548, 31069, 9302, 585, 30598, 27589, 26963, 7031, 3649, 22111, 22881, 10414, 13363, 19419, 27120, 14253, 16880, 27899, 29405, 2500, 26339, 28353, 19006, 10147, 17717, 23548, 9975, 14012, 26717, 24686, 22282, 29602, 20487, 14060, 11487, 11640, 27247,\n17937, 12188, 26959, 8459, 23324, 17487, 6498, 12099, 2120, 22420, 5551, 3509, 4281, 29326, 27625, 12910, 14816, 16537, 13979, 27687, 15200, 19592, 15123, 12851, 29323, 30546, 31932, 12495, 25526, 26901, 11904, 21700, 8301, 12739, 11604, 12805, 21343, 31274, 3590, 11089, 9728, 24044, 1110, 30789, 21445, 17367, 12791, 27356, 26643, 7685, 14717, 23983, 23482, 223, 28151, 17735, 29071, 11631, 30091, 1844, 24248, 24452, 11384, 16674, 28266, 7530, 11551, 23704, 623, 17631, 3793, 25360, 18000, 23308, 20446, 23867, 17304, 11165, 10174, 4484, 925, 9199, 9800, 26485, 15050, 17498, 29724, 6691, 18871, 16308, 30167, 29545, 9424, 28865, 18024, 23357, 27364, 32607, 20749, 16082, 16470, 15824, 19470, 1122, 16289, 11445, 15427, 12303, 8280, 16260, 21593, 16582, 30978, 6061, 11674, 11022, 30252, 30658, 15398, 13373, 9448, 5266, 2309, 19566, 21737, 1191, 29023, 7764, 27011, 16062, 14728, 25888, 15701, 22080, 20470, 26520, 18383, 5007, 5904, 1641, 5296, 29506, 24278, 11125, 21934, 267, 31281, 23044, 28428, 21159, 3593, 29389, 31404, 21816, 32252, 8440, 4050, 4556, 31095, 16830, 13099, 20462, 472, 24826, 29698, 27329, 10587, 15091, 463, 15413, 5980, 7712, 10896, 27470, 8859, 30812, 18377, 5288, 24315, 16265, 27800, 19863, 6883, 13602, 25178, 24250, 13936, 21549, 16441, 17328, 4739, 31858, 25942, 18640, 14999, 3543, 4311, 15920, 14004, 18801, 25211, 32691, 1192, 23211, 11282, 32224, 30275, 23381, 29521, 32534, 21670, 13044, 4585, 28947, 25193, 17195, 25421, 23918, 8593, 11086, 15300, 22560, 15383, 6489, 25015, 28231, 25287, 4249, 26570, 6239, 19216, 20623, 3998, 18251, 2467, 1086, 20921, 20223, 5910, 30125, 1423, 9473, 21994, 17242, 18512, 28454, 10253, 8205, 32007, 23825, 2682, 18462, 27141, 4479, 15110, 25855, 20221, 32556, 11685, 1787, 10529, 27902, 8586, 32633, 28342, 26529, 16566, 12513, 18649, 12071, 23346, 20964, 32180, 7562, 24891, 12009, 11924, 23484, 5080, 7044, 18663, 1891, 19966, 25497, 8576, 17067, 9482, 1664, 10815, 20409, 17900, 14404, 20674, 32473, 32021, 11889, 7192, 27300, 27887, 20849, 23139, 26509, 26583, 183, 17044, 25085, 10148, 19757, 18657, 25375, 18404, 15563, 31045, 23719, 25833, 1347, 16203, 17146, 22054, 5078, 15500, 5559, 18575, 9775, 14044, 29535, 6201, 30970, 7408, 8397, 3639, 6808, 25661, 16986, 29083, 11344, 17563, 15777, 20387, 6722, 31618, 15933, 26974, 21516, 13154, 17178, 28631, 25206, 4445, 7630, 12348, 30582, 8134, 20737, 21326, 28837, 16424, 15329, 15537, 8632, 11399, 901, 24073, 15916, 24480, 23287, 20685, 22416, 20884, 19888, 23441, 3784, 5073, 9030, 16509, 26349, 30268, 32105, 21674, 14257, 16110, 11937, 25160, 25259, 13872, 30259, 8424, 29453, 13954, 6625, 2791, 18862, 10505, 14492, 22784, 14069, 25070, 13389, 13754, 10520 };"
  },
  {
    "path": "SoA/VoxelUtils.h",
    "content": "#pragma once\n\ntemplate <typename T>\ninline T getXFromBlockIndex(T blockIndex) {\n    return blockIndex & 0x1f;\n}\n\ntemplate <typename T>\ninline T getYFromBlockIndex(T blockIndex) {\n    return blockIndex >> 10;\n}\n\ntemplate <typename T>\ninline T getZFromBlockIndex(T blockIndex) {\n    return (blockIndex >> 5) & 0x1f;\n}\n\ntemplate <typename T>\ninline void getPosFromBlockIndex(T blockIndex, T& x, T& y, T& z) {\n    x = blockIndex & 0x1f;\n    y = blockIndex >> 10;\n    z = (blockIndex >> 5) & 0x1f;\n}\n\ntemplate <typename T>\ninline void getPosFromBlockIndex(T blockIndex, glm::tvec3<T>& pos) {\n    pos.x = blockIndex & 0x1f;\n    pos.y = blockIndex >> 10;\n    pos.z = (blockIndex >> 5) & 0x1f;\n}\n\ntemplate <typename T>\ninline i32v3 getPosFromBlockIndex(T blockIndex) {\n    return i32v3(blockIndex & 0x1f, blockIndex >> 10, (blockIndex >> 5) & 0x1f);\n}\nstatic_assert(CHUNK_WIDTH == 32, \"getPosFromBlockIndex assumes 32 chunk width\");\n\ntemplate <typename T>\ninline int getBlockIndexFromPos(T x, T y, T z) {\n    return x | (y << 10) | (z << 5);\n}\n\ntemplate <typename T>\ninline int getBlockIndexFromPos(const T& pos) {\n    return pos.x | (pos.y << 10) | (pos.z << 5);\n}"
  },
  {
    "path": "SoA/VoxelVertices.h",
    "content": "///\n/// VoxelVertices.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 24 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Vertex structs for different voxel types\n///\n\n#pragma once\n\n#ifndef VoxelVertices_h__\n#define VoxelVertices_h__\n\nstruct VertexVoxelChunkSolid {\npublic:\n    ui8v3 pos; ///< Position within its grid\n    /// TODO: More\n};\n\n\n#endif // VoxelVertices_h__"
  },
  {
    "path": "SoA/WSO.cpp",
    "content": "#include \"stdafx.h\"\n#include \"WSO.h\"\n\nWSO::WSO(const WSOData* wsoData, const f64v3& pos) :\nposition(pos),\ndata(wsoData) {\n}\nWSO::~WSO() {\n    // We Don't Have Any Allocated Resources Yet\n}\n"
  },
  {
    "path": "SoA/WSO.h",
    "content": "#pragma once\nclass WSOData;\n\n#include <Vorb/types.h>\n\nclass WSO {\npublic:\n    WSO(const WSOData* wsoData, const f64v3& pos);\n    ~WSO();\n\n    const f64v3 position;\n    const WSOData* const data;\n};"
  },
  {
    "path": "SoA/WSOAtlas.cpp",
    "content": "#include \"stdafx.h\"\n#include \"WSOAtlas.h\"\n\n#include <Vorb/io/IOManager.h>\n\n#include \"WSOData.h\"\n\n// This Information Is Found At The Beginning Of The WSO File\nclass WSOFileHeader {\npublic:\n    // The Size Of DATA Segment\n    i32 dataSegmentSize;\n    // Amount Of WSO Index Information To Read\n    i32 wsoCount;\n};\n// This Is Information About A WSO\nclass WSOIndexInformation {\npublic:\n    // Location In The File\n    i32 fileOffset;\n    // Amount Of Data To Read\n    i32v3 size;\n\n    // The Length Of The String Of The WSO's Name\n    i32 lenName;\n    // The Length Of The String Of The WSO's Model File (If Any)\n    i32 lenModelFile;\n};\n\nWSOAtlas::WSOAtlas() {\n    // Guess What... I Don't Have To Do Anything\n}\nWSOAtlas::~WSOAtlas() {\n    // Dang... Now I Have Work To Do\n    clear();\n}\n\nvoid WSOAtlas::add(WSOData* data) {\n    // Set Its Index\n    data->index = _data.size();\n\n    // Place In The Data\n    _data.push_back(data);\n\n    // Add By Name\n    _mapName[data->name] = data;\n}\n\nvoid WSOAtlas::load(const cString file) {\n    vio::IOManager iom;\n\n    // Attempt To Open The File\n    vfstream f = iom.openFile(file, vio::FileOpenFlags::READ_ONLY_EXISTING | vio::FileOpenFlags::BINARY);\n    if (!f.isOpened()) return;\n\n    // Read The Header\n    WSOFileHeader header;\n    f.read(1, sizeof(WSOFileHeader), &header);\n\n    // Read All The Index Information\n    WSOIndexInformation* indices = new WSOIndexInformation[header.wsoCount];\n    f.read(header.wsoCount, sizeof(WSOIndexInformation), indices);\n\n    // Read The DATA Segment\n    ubyte* data = new ubyte[header.dataSegmentSize];\n    f.read(header.dataSegmentSize, sizeof(ubyte), data);\n\n    // Close The File\n    f.close();\n\n    // Allocate Memory For All The WSO Data\n    WSOData* wsoData = new WSOData[header.wsoCount]();\n    _allocatedMem.push_back(wsoData);\n\n    // Calculate Block Sizes For WSOs\n    i32 nameBlockSize = 0, modelFileBlockSize = 0, idBlockSize = 0;\n    for (i32 i = 0; i < header.wsoCount; i++) {\n        nameBlockSize += indices[i].lenName;\n        modelFileBlockSize += indices[i].lenModelFile;\n        idBlockSize += indices[i].size.x * indices[i].size.y * indices[i].size.z;\n    }\n\n    // Allocate Memory For Names\n    nameBlockSize += header.wsoCount;\n    cString names = new char[nameBlockSize];\n    _allocatedMem.push_back(names);\n\n    // Allocate Memory For Model Files\n    modelFileBlockSize += header.wsoCount;\n    cString modelFiles = new char[modelFileBlockSize];\n    _allocatedMem.push_back(modelFiles);\n    \n    // Allocate Memory For IDs\n    i16* ids = new i16[idBlockSize];\n    _allocatedMem.push_back(ids);\n\n    // Create All The WSOs\n    for (i32 i = 0; i < header.wsoCount; i++) {\n        // Find Location In DATA\n        ubyte* wso = data + indices[i].fileOffset;\n        wsoData[i].size = indices[i].size;\n\n        // Copy Over The Name\n        wsoData[i].name = names;\n        memcpy(wsoData[i].name, wso, indices[i].lenName);\n        wsoData[i].name[indices[i].lenName] = 0;\n        names += indices[i].lenName + 1;\n\n        // Move To Model File Portion\n        wso += indices[i].lenName;\n\n        // Copy Over The File (Otherwise Use Voxels As The Default)\n        if (indices[i].lenModelFile > 0) {\n            wsoData[i].modelFile = names;\n            memcpy(wsoData[i].modelFile, wso, indices[i].lenModelFile);\n            wsoData[i].modelFile[indices[i].lenModelFile] = 0;\n            names += indices[i].lenModelFile + 1;\n\n            // Move To ID Portion\n            wso += indices[i].lenModelFile;\n        }\n        else {\n            wsoData[i].modelFile = nullptr;\n        }\n\n        // Copy Over ID Information\n        wsoData[i].wsoIDs = ids;\n        i32 idSize = wsoData[i].getBlockCount() * sizeof(i16);\n        memcpy(wsoData[i].wsoIDs, wso, idSize);\n        ids += wsoData[i].getBlockCount();\n\n        // Add This Into The Atlas\n        add(wsoData + i);\n    }\n\n    // Delete File Info\n    delete[] indices;\n    delete[] data;\n}\n\nvoid WSOAtlas::clear() {\n    // Free All The Allocated Memory\n//    for (i32 i = _allocatedMem.size() - 1; i >= 0; i--) {\n//        delete[] _allocatedMem[i];\n//    }\n    if(_allocatedMem.size() == 4)\n    {\n        delete (WSOData*)_allocatedMem[0];\n        delete (cString)_allocatedMem[1];\n        delete (cString)_allocatedMem[2];\n        delete (i16*)_allocatedMem[3];\n    }\n\n    // Clear ADT Memory\n    std::vector<WSOData*>().swap(_data);\n    std::map<nString, WSOData*>().swap(_mapName);\n    std::vector<void*>().swap(_allocatedMem);\n}"
  },
  {
    "path": "SoA/WSOAtlas.h",
    "content": "#pragma once\nclass WSOData;\n\n#include <Vorb/types.h>\n/************************************************************************/\n/* WSO File Specification                                               */\n/* FileSpecs\\WSO.txt                                                    */\n/************************************************************************/\n\nclass WSOAtlas {\npublic:\n    WSOAtlas();\n    ~WSOAtlas();\n\n    // Add Data To Atlas (But Memory Is Not Associated With It)\n    void add(WSOData* data);\n\n    // Load WSO Data From A File\n    void load(const cString file);\n\n    // Destroy All Memory Associated With This Atlas\n    void clear();\n\n    // The Number Of Data In The Atlas\n    ui32 getSize() const {\n        return _data.size();\n    }\n\n    // Retrieve Data From The Atlas\n    WSOData* get(const size_t& index) const {\n        return _data[index];\n    }\n    WSOData* operator[] (const size_t& index) const {\n        return get(index);\n    }\n    WSOData* get(nString name) const {\n        return _mapName.at(name);\n    }\n    WSOData* operator[] (nString name) const {\n        return get(name);\n    }\nprivate:\n    // Pointers To All The Data\n    std::vector<WSOData*> _data;\n\n    // Access Data By A Name\n    std::map<nString, WSOData*> _mapName;\n\n    // Pointers To Allocated Memory Blocks\n    std::vector<void*> _allocatedMem;\n};"
  },
  {
    "path": "SoA/WSOData.h",
    "content": "#pragma once\n\nconst i16 WSO_DONT_CARE_ID = (i16)0xffff;\n#define WSO_MAX_SIZE 8\n#define WSO_NAME_MAX_LENGTH 128\n\n// Stores All Combinations Of A WSO\nclass WSOData {\npublic:\n    // The Number Of Blocks Inside This WSO\n    i32 getBlockCount() const {\n        return size.x * size.y * size.z;\n    }\n\n    // The Name Of This WSO\n    cString name;\n\n    // The Index Of This WSO In The Atlas\n    i32 index;\n\n    // Necessary IDs For The WSO To Exist\n    i16* wsoIDs;\n\n    // The Size Of The WSO\n    i32v3 size;\n\n    // The Model File (If It Wants One)\n    cString modelFile;\n};"
  },
  {
    "path": "SoA/WSOScanner.cpp",
    "content": "#include \"stdafx.h\"\n#include \"WSOScanner.h\"\n\n#include \"WSO.h\"\n#include \"WSOAtlas.h\"\n#include \"WSOData.h\"\n#include \"ChunkGrid.h\"\n\n// Scan A Radius Of (WSO_MAX_SIZE - 1) From The Center Block\nconst int WSO_QUERY_SIZE = WSO_MAX_SIZE * 2 - 1;\n\nWSOScanner::WSOScanner(WSOAtlas* atlas VORB_UNUSED) //:\n//_wsoAtlas(atlas) \n{\n    // TODO: Revisit this.\n}\n\nbool checkForWSO(const i16* query, const WSOData* data, i32v3& offset) {\n    i32v3 minPos(WSO_MAX_SIZE);\n    minPos -= data->size;\n    i32v3 localOff;\n\n    // TODO: Check Y-Rotations\n\n    // Loop Through Offsets\n    for (offset.y = minPos.y; offset.y < WSO_MAX_SIZE; offset.y++) {\n        for (offset.z = minPos.z; offset.z < WSO_MAX_SIZE; offset.z++) {\n            for (offset.x = minPos.x; offset.x < WSO_MAX_SIZE; offset.x++) {\n\n                // Try To Find A WSO At This Offset\n                i32v3 maxPos(offset + data->size);\n                bool isOK = true;\n                i32 dataIndex = 0;\n                for (localOff.y = offset.y; localOff.y < maxPos.y && isOK; localOff.y++) {\n                    for (localOff.z = offset.z; localOff.z < maxPos.z && isOK; localOff.z++) {\n                        for (localOff.x = offset.x; localOff.x < maxPos.x && isOK; localOff.x++) {\n                            if (data->wsoIDs[dataIndex] != WSO_DONT_CARE_ID) {\n                                i32 qIndex = (localOff.y * WSO_QUERY_SIZE + localOff.z) * WSO_QUERY_SIZE + localOff.x;\n                                i16 id = query[qIndex];\n\n                                if (data->wsoIDs[dataIndex] != id)\n                                    isOK = false;\n                                else\n                                    printf(\"I Found One Charlie %d\\n\", dataIndex);\n                            }\n                            else\n                                printf(\"I Don't Care Charlie %d\\n\", dataIndex);\n                            dataIndex++;\n                        }\n                    }\n                }\n\n                // All Requirements Of WSO Are Met\n                if (isOK) return true;\n            }\n        }\n    }\n\n    // Could Not Find A Single One\n    return false;\n}\nstd::vector<WSO*> WSOScanner::scanWSOs(const i32v3& position VORB_UNUSED, ChunkGrid* cg VORB_UNUSED) {\n    // TODO: Fix this and remove unused tags.\n    //// Get A Piece Of The World\n    //const i16* query = getQuery(position, cg);\n\n    //std::vector<WSO*> wsos;\n\n    //// Loop Through All Possible WSOs\n    //i32v3 offset;\n    //for (i32 i = _wsoAtlas->getSize() - 1; i >= 0; i--) {\n    //    WSOData* data = _wsoAtlas->get(i);\n    //    if (checkForWSO(query, data, offset)) {\n    //        i32v3 localPos = offset - i32v3(WSO_MAX_SIZE - 1);\n    //        localPos += position;\n\n    //        // This Is A Possible WSO\n    //        //TODO(Cristian) Make this work for new chunkmanager mapping\n    //        //WSO* wso = new WSO(data, f64v3(localPos + cm->cornerPosition));\n    //        //wsos.push_back(wso);\n    //    }\n    //}\n\n    //// TODO: Make Sure We Don't Get Already Created WSOs\n\n    //delete query;\n    //return wsos;\n    return std::vector<WSO*>();\n}\n\nconst i16* WSOScanner::getQuery(const i32v3& position VORB_UNUSED, ChunkGrid* cg VORB_UNUSED) {\n    // TODO: Fix this and remove tags.\n    //// Get The Query Based Off Of The Max Size Of The WSO\n    //const i32v3 minPos = position - i32v3(WSO_MAX_SIZE - 1);\n    //const i32v3 maxPos = position + i32v3(WSO_MAX_SIZE - 1);\n    //return cg->getIDQuery(minPos, maxPos);\n    return nullptr;\n}\n"
  },
  {
    "path": "SoA/WSOScanner.h",
    "content": "#pragma once\n\n#include <Vorb/types.h>\n\nclass ChunkGrid;\nclass WSO;\nclass WSOAtlas;\n\n// A Scanner That Uses An Atlas Of Known WSOs To Attempt Find WSOs\nclass WSOScanner {\npublic:\n    // A Scanner Begins Its Life Knowing About A Certain Atlas\n    WSOScanner(WSOAtlas* atlas);\n\n    // Retrieve All The WSOs\n    std::vector<WSO*> scanWSOs(const i32v3& position, ChunkGrid* cm);\nprivate:\n    // Obtain A Box Volume Of Voxel IDs\n    const i16* getQuery(const i32v3& position, ChunkGrid* cm);\n\n    // This Does Not Have To Point To A Global Atlas Necessarily ;)\n//    WSOAtlas* _wsoAtlas;\n};"
  },
  {
    "path": "SoA/WorldIO.cpp",
    "content": "#include \"stdafx.h\"\n#include \"WorldIO.h\"\n\n#include <direct.h> //for mkdir windows\n#include <dirent.h>\n#include <fcntl.h>\n#include <io.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n\n#include <ZLIB/zlib.h>\n\n#include \"BlockData.h\"\n#include \"Chunk.h\"\n#include \"Errors.h\"\n#include \"FileSystem.h\"\n#include \"GameManager.h\"\n#include \"Options.h\"\n#include \"Planet.h\"\n#include \"Player.h\"\n\n//#define EXTRACTINT(a, i) ( (((GLuint)((GLubyte *)(a))[(i)]) << 24 ) | (((GLuint)((GLubyte *)(a))[(i)+1]) << 16) | (((GLuint)((GLubyte *)(a))[(i)+2]) << 8) | ((GLuint)((GLubyte *)(a))[(i)+3]) )\n\nvoid ThreadError(string msg){\n    cout << msg << endl;\n    pError(msg.c_str());\n}\n\nWorldIO::WorldIO()\n{\n    _maxLocationBufferCacheSize = 15;\n    _currReg = \"\";\n    _isThreadFinished = 0;\n    _isDirtyLocationBuffer = 0;\n    _currLocationBuffer = NULL;\n    readWriteThread = NULL;\n    _threadFile = NULL;\n    _shouldDisableLoading = 0;\n}\n\nWorldIO::~WorldIO()\n{\n    onQuit();\n}\n\nvoid WorldIO::compressBlockData(Chunk *ch)\n{\n    GLushort *blockData = ch->data;\n    GLubyte *lightData = ch->lightData[0];\n\n    _bufferSize = 0;\n    \n    GLushort curr;\n    GLubyte currb;\n    GLuint count = 1;\n    int c;\n    int jStart, jEnd, jInc;\n    int kStart, kEnd, kInc;\n    int jMult, kMult;\n\n    switch(ch->faceData.rotation){ //we use rotation value to un-rotate the chunk data\n        case 0: //no rotation\n            jStart = 0;\n            kStart = 0;\n            jEnd = kEnd = CHUNK_WIDTH;\n            jInc = kInc = 1;\n            jMult = CHUNK_WIDTH;\n            kMult = 1;\n            break;\n        case 1: //up is right\n            jMult = 1;\n            jStart = CHUNK_WIDTH-1;\n            jEnd = -1;\n            jInc = -1;\n            kStart = 0;\n            kEnd = CHUNK_WIDTH;\n            kInc = 1;\n            kMult = CHUNK_WIDTH;\n            break;\n        case 2: //up is down\n            jMult = CHUNK_WIDTH;\n            jStart = CHUNK_WIDTH-1;\n            kStart = CHUNK_WIDTH-1;\n            jEnd = kEnd = -1;\n            jInc = kInc = -1;\n            kMult = 1;\n            break; \n        case 3: //up is left\n            jMult = 1;\n            jStart = 0;\n            jEnd = CHUNK_WIDTH;\n            jInc = 1;\n            kMult = CHUNK_WIDTH;\n            kStart = CHUNK_WIDTH-1;\n            kEnd = -1;\n            kInc = -1;\n            break;\n    }\n\n    curr = blockData[jStart*jMult + kStart*kMult];\n\n    bool first = 1;\n    //compress and store block ID data\n    for (int i = 0; i < CHUNK_WIDTH; i++){ //y\n        for (int j = jStart; j != jEnd; j+=jInc){ //z\n            for (int k = kStart; k != kEnd; k+=kInc){ //x \n                if (!first){ //have to ignore the first one since we set it above\n                    c = i*CHUNK_LAYER + j*jMult + k*kMult; //sometimes x is treated like z and visa versa when rotating\n                    if (blockData[c] != curr){\n                        _byteBuffer[_bufferSize++] = (GLubyte)((count & 0xFF00) >> 8);\n                        _byteBuffer[_bufferSize++] = (GLubyte)(count & 0xFF);\n                        _byteBuffer[_bufferSize++] = (GLubyte)((curr & 0xFF00) >> 8);\n                        _byteBuffer[_bufferSize++] = (GLubyte)(curr & 0xFF);\n\n                        curr = blockData[c];\n                        count = 1;\n                    }else{\n                        count++;\n                    }\n                }else{\n                    first = 0;\n                }\n            }\n        }\n    }\n    _byteBuffer[_bufferSize++] = (GLubyte)((count & 0xFF00) >> 8);\n    _byteBuffer[_bufferSize++] = (GLubyte)(count & 0xFF);\n    _byteBuffer[_bufferSize++] = (GLubyte)((curr & 0xFF00) >> 8);\n    _byteBuffer[_bufferSize++] = (GLubyte)(curr & 0xFF);\n\n    //compress and store artificial light\n    count = 1;\n    currb = lightData[jStart*jMult + kStart*kMult];\n    first = 1;\n    for (int i = 0; i < CHUNK_WIDTH; i++){ //y\n        for (int j = jStart; j != jEnd; j+=jInc){ //z\n            for (int k = kStart; k != kEnd; k+=kInc){ //x \n                if (!first){ //have to ignore the first one since we set it above\n                    c = i*CHUNK_LAYER + j*jMult + k*kMult;\n                    if (lightData[c] != currb){ //remove the count ==???\n                        _byteBuffer[_bufferSize++] = (GLubyte)((count & 0xFF00)>>8);\n                        _byteBuffer[_bufferSize++] = (GLubyte)(count & 0xFF);\n                        _byteBuffer[_bufferSize++] = currb;\n\n                        currb = lightData[c];\n                        count = 1;\n                    }else{\n                        count++;\n                    }\n                }else{\n                    first = 0;\n                }\n            }\n        }\n    }\n    _byteBuffer[_bufferSize++] = (GLubyte)((count & 0xFF00)>>8);\n    _byteBuffer[_bufferSize++] = (GLubyte)(count & 0xFF);\n    _byteBuffer[_bufferSize++] = currb;\n\n    //compress and store voxel sunlight\n    count = 1;\n    currb = lightData[CHUNK_SIZE + jStart*jMult + kStart*kMult];\n    first = 1;\n    for (int i = 0; i < CHUNK_WIDTH; i++){ //y\n        for (int j = jStart; j != jEnd; j+=jInc){ //z\n            for (int k = kStart; k != kEnd; k+=kInc){ //x \n                if (!first){ //have to ignore the first one since we set it above\n                    c = i*CHUNK_LAYER + j*jMult + k*kMult;\n                    if (lightData[CHUNK_SIZE + c] != currb){ //remove the count ==???\n                        _byteBuffer[_bufferSize++] = (GLubyte)((count & 0xFF00)>>8);\n                        _byteBuffer[_bufferSize++] = (GLubyte)(count & 0xFF);\n                        _byteBuffer[_bufferSize++] = currb;\n\n                        currb = lightData[CHUNK_SIZE + c];\n                        count = 1;\n                    }else{\n                        count++;\n                    }\n                }else{\n                    first = 0;\n                }\n            }\n        }\n    }\n    _byteBuffer[_bufferSize++] = (GLubyte)((count & 0xFF00)>>8);\n    _byteBuffer[_bufferSize++] = (GLubyte)(count & 0xFF);\n    _byteBuffer[_bufferSize++] = currb;\n\n    for (int j = jStart; j != jEnd; j+=jInc){ //z\n        for (int k = kStart; k != kEnd; k+=kInc){ //x \n            c = j*jMult + k*kMult;\n            _byteBuffer[_bufferSize++] = ((GLubyte *)ch->sunLight)[c];\n        }\n    }\n\n    if (_bufferSize >= 524288){\n        cout << \"ITS THE BUFFER SIZE DAMMIT \";\n        cout << _bufferSize << endl;\n        int a;\n        cin >> a;\n    }\n    \n    _compressedSize = CRW_BYTE_BUFSIZE + 16 + 52430;\n    int zresult = compress2(&(_compressedByteBuffer[4]), &_compressedSize, _byteBuffer, _bufferSize, 6);\n    \n    //set the size bytes\n    _compressedByteBuffer[0] = (GLubyte)((_compressedSize & 0xFF000000) >> 24);\n    _compressedByteBuffer[1] = (GLubyte)((_compressedSize & 0x00FF0000) >> 16);\n    _compressedByteBuffer[2] = (GLubyte)((_compressedSize & 0x0000FF00) >> 8);\n    _compressedByteBuffer[3] = (GLubyte)(_compressedSize & 0x000000FF);\n    _compressedSize += 4; //add size of size bytes\n\n    switch( zresult )\n    {\n    case Z_MEM_ERROR:\n        ThreadError(\"zlib compression: out of memory\\n\");\n        exit(1);    // quit.\n    case Z_BUF_ERROR:\n        ThreadError(\"zlib compression: output buffer wasn't large enough\\n\");\n        exit(1);    // quit.\n    }\n}\n\nint WorldIO::saveToFile(Chunk *ch)\n{\n    GLuint offset;\n    GLuint bufSize = 0;\n    GLubyte *endDataBuffer = NULL;\n    int sizeDiff = 0;\n    GLuint padLength;\n    GLuint endDataBufferSize = 0;\n\n    compressBlockData(ch);\n\n    _chunkLength = _compressedSize; //size of our new chunk\n    padLength = SECTOR_SIZE - _chunkLength%SECTOR_SIZE;\n    if (padLength == SECTOR_SIZE) padLength = 0;\n    _chunkLength += padLength; //pad the length\n\n    //try to seek to location\n    seekToChunkOffset(ch);\n\n    GLuint num;\n    GLuint newBlockSize = _chunkLength/SECTOR_SIZE;\n    if (newBlockSize > _chunkBlockSize || newBlockSize < _chunkBlockSize) // if we need more or fewer blocks\n    {\n        sizeDiff = newBlockSize - _chunkBlockSize;\n        bufSize = _fileSize/SECTOR_SIZE - (_chunkOffset + _chunkBlockSize); //number of blocks to copy\n        if (bufSize != 0){ //check if there is stuff after us that will be displaced\n            endDataBuffer = new GLubyte[bufSize*SECTOR_SIZE]; //for storing all the data that will need to be copied in the end\n            endDataBufferSize = bufSize*SECTOR_SIZE;\n\n            if (fseek(_threadFile, _fileSize - bufSize*SECTOR_SIZE, SEEK_SET) != 0){\n                cout << \"Region: Chunk data fseek C error! \" << _fileSize << \" \" << bufSize << \" \" << _fileSize - bufSize*SECTOR_SIZE << endl;\n            }\n\n            num = 8192;\n            for (GLuint i = 0; i < endDataBufferSize; i+= 8192){\n                if (endDataBufferSize - i < num){\n                    padLength = SECTOR_SIZE - (endDataBufferSize-i)%SECTOR_SIZE;\n                    if (padLength == SECTOR_SIZE) padLength = 0;\n                    num = endDataBufferSize-i + padLength;\n                }\n                if (fread(&(endDataBuffer[i]), 1, num, _threadFile) != num){\n                    cout << \"Did not read enough bytes at A\\n\";\n                }\n            }\n        }\n    }\n    \n    if (fseek(_threadFile, _chunkOffset*SECTOR_SIZE, SEEK_SET) != 0){\n        cout << \"Region: Chunk data fseek D error! \" << _fileSize << \" \" << _chunkOffset << \" \" << _chunkOffset*SECTOR_SIZE << endl;\n        int a;\n        cin >> a;\n    }\n    \n    //write data\n    num = 8192;\n    for (GLuint i = 0; i < _compressedSize; i += 8192){\n        if (_compressedSize - i < num){\n            padLength = SECTOR_SIZE - (_compressedSize-i)%SECTOR_SIZE;\n            if (padLength == SECTOR_SIZE) padLength = 0;\n            num = _compressedSize-i + padLength;\n        }\n        if (fwrite(&(_compressedByteBuffer[i]), 1, num, _threadFile) != num){\n            cout << \"Did not write enough bytes at A\\n\";\n        }\n    }\n\n    //write leftover data\n    num = 8192;\n    for (GLuint i = 0; i < endDataBufferSize; i+= 8192){\n        if (endDataBufferSize - i < num){\n            padLength = SECTOR_SIZE - (endDataBufferSize-i)%SECTOR_SIZE;\n            if (padLength == SECTOR_SIZE) padLength = 0;\n            num = endDataBufferSize-i + padLength;\n        }\n        if (fwrite(&(endDataBuffer[i]), 1, num, _threadFile) != num){\n            cout << \"Did not write enough bytes at B\\n\";\n        }\n            \n    }\n\n    if (sizeDiff < 0){ //if the file got smaller\n        if (truncate(_fileSize + sizeDiff*SECTOR_SIZE) != 0){ //truncate the size\n            cout << \"Region: Truncate error!\\n\";\n            perror(\" region file \");\n        }\n    }\n\n    _fileSize = _fileSize + sizeDiff*SECTOR_SIZE;\n\n    GLuint location;\n    location = extractInt(_currLocationBuffer->buffer, _locOffset);\n    offset = (location >> 8);\n    if (offset != _chunkOffset){\n        _currLocationBuffer->buffer[_locOffset] = (GLubyte)((_chunkOffset & 0xFF0000) >> 16);\n        _currLocationBuffer->buffer[_locOffset + 1] = (GLubyte)((_chunkOffset & 0xFF00) >> 8);\n        _currLocationBuffer->buffer[_locOffset + 2] = (GLubyte)(_chunkOffset & 0xFF);\n        _isDirtyLocationBuffer = 1;\n    }\n    if (_chunkBlockSize != newBlockSize){\n        _currLocationBuffer->buffer[_locOffset + 3] = (GLubyte)newBlockSize; //set the blockSize\n        _isDirtyLocationBuffer = 1;\n    }\n\n    //update the table\n    if (bufSize != 0){\n        for (int i = 0; i < 16384; i+=4){\n            location = extractInt(_currLocationBuffer->buffer, i);\n            offset = (location >> 8);\n            if (offset > _chunkOffset){ //if its an in use chunk\n                offset += sizeDiff;\n                _currLocationBuffer->buffer[i] = (GLubyte)((offset & 0xFF0000) >> 16);\n                _currLocationBuffer->buffer[i + 1] = (GLubyte)((offset & 0xFF00) >> 8);\n                _currLocationBuffer->buffer[i + 2] = (GLubyte)(offset & 0xFF);\n                _isDirtyLocationBuffer = 1;\n            }\n        }\n    }\n\n    if (_isDirtyLocationBuffer){\n        fseek(_threadFile, 0, SEEK_SET); //go back to beginning of file to save the table\n        fwrite(_currLocationBuffer->buffer, 1, 16384, _threadFile);\n        _isDirtyLocationBuffer = 0;\n    }\n\n    fflush(_threadFile);\n    \n    if (endDataBuffer){\n        delete[] endDataBuffer; //no longer need the buffer\n    }\n\n    return 0;\n}\n\nint WorldIO::loadFromFile(Chunk *ch)\n{\n    _locOffset = getLocOffset(ch);\n\n    GLuint location = extractInt(_currLocationBuffer->buffer, _locOffset);\n    _chunkOffset = (location >> 8);//grab the 3 offset bytes\n    _chunkBlockSize = (location & 0xFF);//grab the block size byte\n    if (_chunkOffset == 0){\n        //Error((\"TRIED TO LOAD CHUNK WITH NO OFFSET \" + to_string(locOffset) + \" \" + to_string(location) + \" \" + currReg).c_str());\n        cout << \"Nonfatal error: TRIED TO LOAD CHUNK WITH NO OFFSET \" + to_string(_locOffset) + \" \" + to_string(location) + \" \" + _currReg << endl;\n        return 1;\n    }\n    if (fseek(_threadFile, _chunkOffset*SECTOR_SIZE, SEEK_SET) != 0){\n        cout << \"Region: Chunk data fseek C error! \" << _fileSize << \" \" << _chunkOffset << \" \" << _chunkOffset*SECTOR_SIZE << \" \" << _threadFile << endl;\n        return 1;\n    }\n\n    int num = 8192;\n    int padLength;\n    int size = _chunkBlockSize*SECTOR_SIZE;\n    if (size >= 262144)pError(\"Region input Byte Buffer overflow\");\n    for (int i = 0; i < size; i+=8192){\n        if (size - i < num){\n            padLength = SECTOR_SIZE - (size-i)%SECTOR_SIZE;\n            if (padLength == SECTOR_SIZE) padLength = 0;\n            num = size-i + padLength;\n        }\n        if (fread(&(_compressedByteBuffer[i]), 1, num, _threadFile) != num){\n            cout << \"Did not read enough bytes at Z\\n\";\n            return 1;\n        }\n    }\n\n    _bufferSize = CRW_BYTE_BUFSIZE;\n    _compressedSize = extractInt(_compressedByteBuffer, 0); //grab the size int\n    int zresult = uncompress(_byteBuffer, &_bufferSize, &(_compressedByteBuffer[4]), _compressedSize);\n\n    switch( zresult )\n    {\n    case Z_MEM_ERROR:\n        ThreadError(\"zlib uncompression: out of memory\\n\");\n        exit(1);    // quit.\n    case Z_BUF_ERROR:\n        ThreadError(\"zlib uncompression: output buffer wasn't large enough\\n\");\n        exit(1);    // quit.\n    }\n\n    unsigned long b = 0;\n    int step = 0;//0 = data, 1 = lightdata\n\n    //cout << \"READSIZE \" << size << endl;\n\n    GLuint bindex = 0;\n    GLushort blockID;\n    GLushort runSize;\n    GLubyte lightVal;\n\n    int c;\n    int jStart, jEnd, jInc;\n    int kStart, kEnd, kInc;\n    int jMult, kMult;\n\n    switch(ch->faceData.rotation){ //we use rotation value to un-rotate the chunk data\n        case 0: //no rotation\n            jStart = 0;\n            kStart = 0;\n            jEnd = kEnd = CHUNK_WIDTH;\n            jInc = kInc = 1;\n            jMult = CHUNK_WIDTH;\n            kMult = 1;\n            break;\n        case 1: //up is right\n            jMult = 1;\n            jStart = CHUNK_WIDTH-1;\n            jEnd = -1;\n            jInc = -1;\n            kStart = 0;\n            kEnd = CHUNK_WIDTH;\n            kInc = 1;\n            kMult = CHUNK_WIDTH;\n            break;\n        case 2: //up is down\n            jMult = CHUNK_WIDTH;\n            jStart = CHUNK_WIDTH-1;\n            kStart = CHUNK_WIDTH-1;\n            jEnd = kEnd = -1;\n            jInc = kInc = -1;\n            kMult = 1;\n            break; \n        case 3: //up is left\n            jMult = 1;\n            jStart = 0;\n            jEnd = CHUNK_WIDTH;\n            jInc = 1;\n            kMult = CHUNK_WIDTH;\n            kStart = CHUNK_WIDTH-1;\n            kEnd = -1;\n            kInc = -1;\n            break;\n        default:\n            cout << \"ERROR Chunk Loading: Rotation value not 0-3\";\n            int a;\n            cin >> a;\n            return 1;\n            break;\n    }\n\n    int i = 0; //y\n    int j = jStart; //z\n    int k = kStart; //x\n    int sunLightAdd = 0;\n\n    ch->num = 0;\n    while (b < _bufferSize){\n        //blockData\n        if (step == 0){\n            if (b >= 524280) { cout << \"ERROR: Chunk File Corrupted! :( \" << _bufferSize << \" \" << bindex << \" \" << _locOffset << endl; return 1; }\n             runSize = (((GLushort)_byteBuffer[b]) << 8) | ((GLushort)_byteBuffer[b+1]);\n            blockID = (((GLushort)_byteBuffer[b+2]) << 8) | ((GLushort)_byteBuffer[b+3]);\n            if (blockID != 0) ch->num += runSize;\n\n            for (int q = 0; q < runSize; q++){\n                c = i*CHUNK_LAYER + j*jMult + k*kMult;\n                if (c >= CHUNK_SIZE){ cout << \"Chunk File Corrupted!\\n\"; return 1; }\n                ch->data[c] = blockID;\n                if (GETBLOCK(ch->data[c]).spawnerVal || GETBLOCK(ch->data[c]).sinkVal){\n                    ch->activeBlocks.push_back(c);\n                }\n                if (blockID >= LOWWATER && blockID <= FULLWATER) ch->hasWater = 1;\n                bindex++;\n                k += kInc;\n                if (k == kEnd){\n                    k = kStart;\n                    j += jInc;\n                    if (j == jEnd){\n                        j = jStart;\n                        i++;\n                    }\n                }\n            }\n            if (bindex == CHUNK_SIZE){\n                i = 0;\n                j = jStart;\n                k = kStart;\n                step = 1;\n                bindex = 0;\n            }\n            b += 4;\n        }else if (step == 1){ //lightData\n            runSize = (((GLushort)_byteBuffer[b]) << 8) | ((GLushort)_byteBuffer[b+1]);\n            lightVal = _byteBuffer[b+2];\n        \n            for (int q = 0; q < runSize; q++){\n                c = i*CHUNK_LAYER + j*jMult + k*kMult;\n                if (sunLightAdd + c >= CHUNK_SIZE * 2){\n                    cout << \"Corruption when filling light data from loaded chunk.\";\n                    return 1;\n                }\n                ((GLubyte *)(ch->lightData))[sunLightAdd+c] = lightVal;\n                bindex++;\n                k += kInc;\n                if (k == kEnd){\n                    k = kStart;\n                    j += jInc;\n                    if (j == jEnd){\n                        j = jStart;\n                        i++;\n                    }\n                }\n                if (bindex == CHUNK_SIZE){ //start over for sunLight\n                    i = 0;\n                    j = jStart;\n                    k = kStart;\n                    sunLightAdd = CHUNK_SIZE;\n                }\n            }\n            if (bindex == CHUNK_SIZE*2){\n                step = 2;\n                bindex = 0;\n            }\n            b += 3;\n        }else{ //sunlights data\n            c = j*jMult + k*kMult;\n            if (c >= 1024){ cout << \"Chunk File Corrupted!\\n\"; return 1; }\n            ch->sunLight[c] = ((GLbyte *)_byteBuffer)[b];\n            bindex++;\n            k += kInc;\n            if (k == kEnd){\n                k = kStart;\n                j += jInc;\n            }\n            b++;\n        //    if (bindex == 1024){\n        //        break;\n        //    }\n        }\n    }\n    if (bindex != 1024){\n        cout << \"ERROR Chunk Loading: bindex went too far! \" << bindex << \" \" << step << endl;\n        return 1;\n    }\n    return 0;\n}\n\nint WorldIO::deleteChunkFile(Chunk *ch)\n{\n    _locOffset = getLocOffset(ch);\n    GLubyte *endDataBuffer = NULL;\n    GLuint endDataBufferSize = 0;\n    GLuint num;\n    int padLength;\n    GLuint location = extractInt(_currLocationBuffer->buffer, _locOffset);\n    _chunkOffset = (location >> 8);//grab the 3 offset bytes\n    _chunkBlockSize = (location & 0xFF);//grab the block size byte\n\n    //clear the spot in the lookup table\n    setInt(_currLocationBuffer->buffer, _locOffset, 0);\n    _isDirtyLocationBuffer = 1;\n\n    int sizeDiff = -((int)_chunkBlockSize);\n    int bufSize = _fileSize / SECTOR_SIZE - (_chunkOffset + _chunkBlockSize); //number of blocks to copy\n    if (bufSize < 0) {\n        cout << \"Save file is corrupted! :( Attempting to recover... but your save may be ruined. I am sorry...\" << endl;\n        bufSize = 0;\n    }\n    if (bufSize != 0){ //check if there is stuff after us that will be displaced\n        endDataBuffer = new GLubyte[bufSize*SECTOR_SIZE]; //for storing all the data that will need to be copied in the end\n        endDataBufferSize = bufSize*SECTOR_SIZE;\n\n        if (fseek(_threadFile, _fileSize - bufSize*SECTOR_SIZE, SEEK_SET) != 0){\n            cout << \"Region: Chunk data fseek C error! \" << _fileSize << \" \" << bufSize << \" \" << _fileSize - bufSize*SECTOR_SIZE << endl;\n            int a;\n            cin >> a;\n        }\n\n        num = 8192;\n        for (GLuint i = 0; i < endDataBufferSize; i += 8192){\n            if (endDataBufferSize - i < num){\n                padLength = SECTOR_SIZE - (endDataBufferSize - i) % SECTOR_SIZE;\n                if (padLength == SECTOR_SIZE) padLength = 0;\n                num = endDataBufferSize - i + padLength;\n            }\n            if (fread(&(endDataBuffer[i]), 1, num, _threadFile) != num){\n                cout << \"Did not read enough bytes at A delete\\n\";\n            }\n        }\n    }\n     //this is the same as save?\n    if (fseek(_threadFile, _chunkOffset*SECTOR_SIZE, SEEK_SET) != 0){\n        cout << \"Region: Chunk data fseek D error! \" << _fileSize << \" \" << _chunkOffset << \" \" << _chunkOffset*SECTOR_SIZE << endl;\n        int a;\n        cin >> a;\n    }\n\n    //write leftover data\n    num = 8192;\n    for (GLuint i = 0; i < endDataBufferSize; i += 8192){\n        if (endDataBufferSize - i < num){\n            padLength = SECTOR_SIZE - (endDataBufferSize - i) % SECTOR_SIZE;\n            if (padLength == SECTOR_SIZE) padLength = 0;\n            num = endDataBufferSize - i + padLength;\n        }\n        if (fwrite(&(endDataBuffer[i]), 1, num, _threadFile) != num){\n            cout << \"Did not write enough bytes at B delete\\n\";\n        }\n\n    }\n\n    if (sizeDiff < 0){ //if the file got smaller\n        if (truncate(_fileSize + sizeDiff*SECTOR_SIZE) != 0){ //truncate the size\n            cout << \"Region: Truncate error!\\n\";\n            perror(\" region file \");\n            int a;\n            cin >> a;\n        }\n    }\n\n    if (_isDirtyLocationBuffer){\n        fseek(_threadFile, 0, SEEK_SET); //go back to beginning of file to save the table\n        fwrite(_currLocationBuffer->buffer, 1, 16384, _threadFile);\n        _isDirtyLocationBuffer = 0;\n    }\n\n\n    fflush(_threadFile);\n    return 0;\n}\n\nint WorldIO::tryReadFromFile()\n{\n    FILE *f;\n    string filePath = \"Saves/Save1/test.soas\";\n    f = fopen(filePath.c_str(), \"rb\");\n    if (f == NULL){\n        pError(\"Could not open test.soas for reading\");\n        return -1;\n    }\n\n    fclose(f);\n    return 0;\n}\n\nvoid WorldIO::addToSaveList(Chunk *ch)\n{\n    if (ch->inSaveThread == 0 && ch->inLoadThread == 0){\n        ch->dirty = 0;\n        string rs = getRegionString(ch);\n        _queueLock.lock();\n        ch->inSaveThread = 1;\n        chunksToSave.push(ch);\n        _queueLock.unlock();\n        _cond.notify_one();\n    }\n}\n\nvoid WorldIO::addToSaveList(vector <Chunk *> &chunks)\n{\n    _queueLock.lock();\n    Chunk *ch;\n    for (size_t i = 0; i < chunks.size(); i++){\n        ch = chunks[i];\n        if (ch->inSaveThread == 0 && ch->inLoadThread == 0){\n            ch->inSaveThread = 1;\n            ch->dirty = 0;\n            chunksToSave.push(ch);\n        }\n    }\n    _queueLock.unlock();\n    _cond.notify_one();\n}\n\nvoid WorldIO::addToLoadList(Chunk *ch)\n{\n    if (ch->inSaveThread == 0 && ch->inLoadThread == 0){\n        _queueLock.lock();\n        ch->loadStatus = 0;\n        ch->inLoadThread = 1;\n        chunksToLoad.push(ch);\n        _queueLock.unlock();\n        _cond.notify_one();\n    }\n}\n\nvoid WorldIO::addToLoadList(vector <Chunk *> &chunks)\n{\n    _queueLock.lock();\n    Chunk *ch;\n\n    if (_shouldDisableLoading) {\n        flcLock.lock();\n        for (size_t i = 0; i < chunks.size(); i++){\n            chunks[i]->loadStatus = 2;\n            finishedLoadChunks.push_back(chunks[i]);\n        }\n        flcLock.unlock();\n        _queueLock.unlock();\n        return;\n    }\n\n    for (size_t i = 0; i < chunks.size(); i++){\n        ch = chunks[i];\n       \n        if (ch->inSaveThread == 0 && ch->inLoadThread == 0){\n            ch->inLoadThread = 1;\n            chunksToLoad.push(ch);\n        }\n        else{\n            cout << \"ERROR: Tried to add chunk to load list and its in a thread! : \" << ch->position.x << \" \" << ch->position.y << \" \" << ch->position.z << endl;\n        }\n    }\n    _queueLock.unlock();\n    _cond.notify_one();\n}\n\nstring WorldIO::getRegionString(Chunk *ch)\n{\n    int rot = ch->faceData.rotation;\n    int face = ch->faceData.face;\n    int idir = FaceOffsets[face][rot][0];\n    int jdir = FaceOffsets[face][rot][1];\n    int ip = (ch->faceData.ipos - GameManager::planet->radius/CHUNK_WIDTH)*idir;\n    int jp = (ch->faceData.jpos - GameManager::planet->radius/CHUNK_WIDTH)*jdir;\n    if (rot%2){ //when rot%2 i and j must switch\n        return \"r.\" + to_string(ip >> 4) + \".\" + to_string((int)floor(ch->position.y / 32.0f) >> 4) + \".\" + to_string(jp >> 4);\n    }else{\n        return \"r.\" + to_string(jp >> 4) + \".\" + to_string((int)floor(ch->position.y / 32.0f) >> 4) + \".\" + to_string(ip >> 4);\n    }\n}\n\nint WorldIO::openRegionFile(string reg, int face, bool create, FILE **file, int &fd)\n{\n    string filePath;\n    struct stat statbuf;\n\n    if (*file != NULL){\n        if (reg != _currReg){\n            if (_isDirtyLocationBuffer){\n\n                if (fseek(*file, 0, SEEK_SET) != 0){ //go back to beginning of file to save the table\n                    ThreadError(\"Fseek error G could not seek to start\\n\");\n                }\n                if (fwrite(_currLocationBuffer->buffer, 1, 16384, *file) != 16384){\n                    ThreadError(\"Region write error G could not write loc buffer\\n\");\n                }\n\n                _isDirtyLocationBuffer = 0;\n            }\n            fclose(*file);\n            *file = NULL;\n        }else{\n            return 0; //the file is already open\n        }\n    }\n\n    _currReg = reg;\n    _isDirtyLocationBuffer = 0;\n\n    //Check to see if the save file has \n\n    filePath = saveFilePath + \"/Region/f\" + to_string(face) + \"/\" + _currReg + \".soar\";\n//    cout << filePath << endl;\n    \n    (*file) = fopen(filePath.c_str(), \"rb+\"); //open file if it exists\n    if (*file == NULL){\n        if (create){\n            (*file) = fopen(filePath.c_str(), \"wb+\"); //create the file\n            if (*file == NULL){\n                return 1;\n            }\n        }else{\n            return 1 ;\n        }\n    }\n    fd = fileno(*file); //get file descriptor for truncate if needed\n\n    if (fstat(fd, &statbuf) != 0) ThreadError(\"Stat call failed for region file open\"); //get the file stats\n    _fileSize = statbuf.st_size;\n    if (_fileSize % SECTOR_SIZE){\n        ThreadError((filePath + \": Save File size must be multiple of \" + to_string(SECTOR_SIZE) + \". Remainder = \" + to_string(_fileSize%SECTOR_SIZE)));\n    }\n    if (_fileSize == 0){ //set up the initial location data\n        _fileSize = 16384;\n\n        _iterLocationCache = _locationCache.find(_currReg);\n        if (_iterLocationCache != _locationCache.end()){\n            _currLocationBuffer = _iterLocationCache->second;\n        }else{\n            _currLocationBuffer = newLocationBuffer();\n        }\n         //initialize to 0\n        memset(_currLocationBuffer->buffer, 0, 16384);\n        if (fwrite(_currLocationBuffer->buffer, 1, 16384, *file) != 16384){\n            ThreadError(\"Region write error F could not write loc buffer\\n\");\n        }\n        \n        fflush(*file);\n    }else{ //load inital location data into memory \n        _iterLocationCache = _locationCache.find(_currReg);\n        if (_iterLocationCache != _locationCache.end()){\n            _currLocationBuffer = _iterLocationCache->second;\n        }else{\n            _currLocationBuffer = newLocationBuffer();\n\n            if (fseek(*file, 0, SEEK_SET) != 0){\n                ThreadError(\"Region fseek error F could not seek to start\\n\");\n            }\n            if (fread(_currLocationBuffer->buffer, 1, 16384, *file) != 16384){ //read the whole buffer in\n                ThreadError(\"Region read error H could not read locbuffer\\n\");\n            }\n        }\n    }\n\n    return 0;\n}\n\nint WorldIO::isChunkSaved(Chunk *ch)\n{\n    //cout << \"RS:\" << reg << \" \";\n    GLuint sLocOffset = getLocOffset(ch);\n\n    int location = extractInt(_currLocationBuffer->buffer, sLocOffset);\n    if (location != 0){\n        return 1;\n    }\n\n\n    return 0;\n}\n\nint WorldIO::seekToChunkOffset(Chunk *ch)\n{\n    GLuint location;\n    GLuint offset;\n\n    _locOffset = getLocOffset(ch);\n        \n    location = extractInt(_currLocationBuffer->buffer, _locOffset);\n    offset = (location >> 8);\n\n    if (offset == 0){ //check to see if the 4 bytes are empty//endianness?\n        _chunkOffset = _fileSize/SECTOR_SIZE; //if its empty, set our offset to the end of the file.\n        _chunkBlockSize = 0; //it has no size\n    }else{\n        _chunkOffset = offset; //grab the 3 offset bytes\n        _chunkBlockSize = _currLocationBuffer->buffer[_locOffset + 3]; //grab the block size byte\n    }\n\n    if (fseek(_threadFile, _chunkOffset*SECTOR_SIZE, SEEK_SET) != 0){  //seek to the chunk location\n        cout << \"Region: Chunk data fseek B error! \" << _fileSize << \" \" << _chunkOffset << \" \" << _chunkOffset*SECTOR_SIZE << \" \" << _threadFile << endl;\n        int a;\n        cin >> a;\n    }\n    return 0;\n}\n\nvoid WorldIO::closeFile()\n{\n    if (_threadFile != NULL) fclose(_threadFile);\n    _threadFile = NULL;\n}\n\ni32 WorldIO::truncate(i64 size)\n{\n#if defined(_WIN32) || defined(_WIN64) \n    return _chsize(_threadFileDescriptors, size);\n#else\n  #ifdef POSIX\n    return ftruncate(fd, size);\n  #else\n    // code for other OSes\n  #endif\n#endif\n}\n\nGLuint WorldIO::getLocOffset(Chunk *ch)\n{\n    int idir = FaceOffsets[ch->faceData.face][ch->faceData.rotation][0];\n    int jdir = FaceOffsets[ch->faceData.face][ch->faceData.rotation][1];\n    int ip = (ch->faceData.ipos - GameManager::planet->radius/CHUNK_WIDTH)*idir;\n    int jp = (ch->faceData.jpos - GameManager::planet->radius/CHUNK_WIDTH)*jdir;\n\n    if (ch->faceData.rotation%2){ //when rot%2 i and j must switch\n        int tmp = ip;\n        ip = jp;\n        jp = tmp;\n    }\n    \n    int ym = ((int)floor(ch->position.y / (float)CHUNK_WIDTH) % 16);\n    int im = ip % 16;\n    int jm = jp % 16;\n\n    if (ym < 0) ym += 16;//modulus is weird in c++ for negative numbers\n    if (im < 0) im += 16;\n    if (jm < 0) jm += 16;\n    GLuint lc = 4*(jm + im * 16 + ym * 256);\n    if (lc >= 16384){\n        cout << \"WRONG LOC OFFSET \" << jm << \" \" << (im) * 16 << \" \" << ym * 256 << \" \" << lc << endl;\n        int a;\n        cin >> a;\n    }\n    return lc;\n}\n\nLocationBuffer *WorldIO::newLocationBuffer()\n{\n    LocationBuffer *locBuf;\n    if (_locationCacheQueue.size() >= _maxLocationBufferCacheSize){\n        locBuf = _locationCacheQueue.front();\n        _locationCacheQueue.pop();\n        auto i = _locationCache.find(locBuf->reg);\n        if (i != _locationCache.end()){\n            _locationCache.erase(locBuf->reg);\n            delete locBuf;\n        }\n\n    }\n\n    locBuf = new LocationBuffer;\n    locBuf->reg = _currReg; //maybe reg should be parameter\n    _locationCache.insert(make_pair(locBuf->reg, locBuf));\n    _locationCacheQueue.push(locBuf);\n    return locBuf;\n}\n\nvoid WorldIO::clearLoadList()\n{\n    _queueLock.lock();\n    queue<Chunk*>().swap(chunksToLoad); //clear the queue\n    _queueLock.unlock();\n}\n\nint WorldIO::getLoadListSize()\n{    \n    return chunksToLoad.size();\n}\n\nint WorldIO::getSaveListSize()\n{\n    int rv;\n    _queueLock.lock();\n    rv = chunksToSave.size();\n    _queueLock.unlock();\n    return rv;\n}\n\nvoid WorldIO::readWriteChunks()\n{\n    unique_lock<mutex> ulock(_queueLock);\n    Chunk *ch;\n    bool failed;\n    string reg;\n    while (!_isDone){\n        if (_isDone){\n            ulock.unlock();\n            _isThreadFinished = 1;\n            return;\n        }\n        _cond.wait(ulock); //wait for a notification that queue is not empty\n\n        if (_isDone){\n            ulock.unlock();\n            _isThreadFinished = 1;\n            return;\n        }\n        while (chunksToLoad.size() || chunksToSave.size()){ //loops through the load and save queues\n            if (chunksToLoad.size()){ //do load list first\n\n                ch = chunksToLoad.front();\n                chunksToLoad.pop();\n                ulock.unlock();\n\n                reg = getRegionString(ch);\n\n                if ((openRegionFile(reg, ch->faceData.face, 0, &_threadFile, _threadFileDescriptors) == 0) && isChunkSaved(ch)){\n                    failed = loadFromFile(ch);\n\n                    if (failed){\n                        ch->loadStatus = 1;\n                        deleteChunkFile(ch);\n                    }\n                }\n                else{\n                    ch->loadStatus = 2; //it isn't saved, so main thread will give it to the generate list.\n                }\n                flcLock.lock();\n                finishedLoadChunks.push_back(ch);\n                flcLock.unlock();\n\n                ulock.lock();\n            }\n            else if (chunksToSave.size()){\n                ch = chunksToSave.front();\n                ulock.unlock();\n\n                reg = getRegionString(ch);\n\n                if (openRegionFile(reg, ch->faceData.face, 1, &_threadFile, _threadFileDescriptors)){\n                    ThreadError(\"OPEN REG ERROR 2\\n\");\n                };\n\n                saveToFile(ch);\n                \n                //dont always do this?\n                if (_isDirtyLocationBuffer){\n                    fseek(_threadFile, 0, SEEK_SET); //go back to beginning of file to save the table\n                    fwrite(_currLocationBuffer->buffer, 1, 16384, _threadFile);\n                    _isDirtyLocationBuffer = 0;\n                }\n                \n                ulock.lock();\n                chunksToSave.pop();\n                ch->inSaveThread = 0; //race condition! make a new queue!\n            }\n        }\n    }\n}\n\nvoid WorldIO::beginThread()\n{\n    _isDone = 0;\n    _currReg = \"\";\n    _isThreadFinished = 0;\n    _isDirtyLocationBuffer = 0;\n    _currLocationBuffer = NULL;\n    readWriteThread = NULL;\n    _threadFile = NULL;\n    readWriteThread = new std::thread(&WorldIO::readWriteChunks, this);\n}\n\nvoid WorldIO::onQuit()\n{\n\n    clearLoadList();\n    while (getSaveListSize() != 0);\n\n    _queueLock.lock();\n    _isDone = 1;\n    _queueLock.unlock();\n    _cond.notify_one();\n    if (readWriteThread != NULL && readWriteThread->joinable()) readWriteThread->join();\n    delete readWriteThread;\n    readWriteThread = NULL;\n\n    if (_threadFile != NULL) fclose(_threadFile);\n    _currLocationBuffer = NULL;\n    _threadFile = NULL;\n    _isDirtyLocationBuffer = 0;\n\n    while (_locationCacheQueue.size()){\n        delete _locationCacheQueue.front();\n        _locationCacheQueue.pop();\n    }\n    _locationCache.clear();\n\n    \n    finishedLoadChunks.clear();\n}"
  },
  {
    "path": "SoA/WorldIO.h",
    "content": "#pragma once\n#include <condition_variable>\n#include <mutex>\n#include <queue>\n#include <thread>\n#include <Windows.h>\n\n#include <Vorb/types.h>\n#include <zconf.h>\n\nclass Chunk;\n\nconst i32 SECTOR_SIZE = 512;\n\nstruct LocationBuffer {\npublic:\n    ui8 buffer[16384];\n    nString reg;\n};\n\nclass WorldIO {\npublic:\n    WorldIO();\n    ~WorldIO();\n\n    void addToSaveList(Chunk* ch);\n    void addToSaveList(std::vector<Chunk*>& chunks);\n    void addToLoadList(Chunk* ch);\n    void addToLoadList(std::vector<Chunk*>& chunks);\n\n    void beginThread();\n\n    i32 isChunkSaved(Chunk* ch);\n    void closeFile();\n\n    void clearLoadList();\n    i32 getLoadListSize();\n    i32 getSaveListSize();\n\n    void onQuit();\n\n    void setDisableLoading(bool disableLoading) {\n        _shouldDisableLoading = disableLoading;\n    }\n\n    std::queue<Chunk*> chunksToLoad;\n    std::queue<Chunk*> chunksToSave; //store by region string\n    std::thread* readWriteThread;\n    std::mutex flcLock;\n    std::vector<Chunk*> finishedLoadChunks;\nprivate:\n    i32 saveToFile(Chunk* ch);\n    i32 loadFromFile(Chunk* ch);\n    i32 deleteChunkFile(Chunk* ch);\n    i32 fillChunkData(Chunk* ch);\n    i32 tryReadFromFile();\n    i32 openRegionFile(nString reg, i32 face, bool create, FILE** file, i32& fd);\n    nString getRegionString(Chunk* ch);\n    void compressBlockData(Chunk* ch);\n    i32 seekToChunkOffset(Chunk* ch);\n    i32 truncate(i64 size);\n    ui32 getLocOffset(Chunk* ch);\n    LocationBuffer* newLocationBuffer();\n\n    void readWriteChunks(); //used by the thread\n\n    std::mutex _queueLock;\n    std::condition_variable _cond;\n\n    FILE* _threadFile;\n    i32 _threadFileDescriptors;\n    nString _currReg;\n\n#define CRW_BYTE_BUFSIZE 524288\n    //These two buffers store the voxel data for block IDs and voxel light\n    ui8 _byteBuffer[CRW_BYTE_BUFSIZE];\n    uLongf _bufferSize;\n    ui8 _compressedByteBuffer[CRW_BYTE_BUFSIZE + 12 + 52430];\n    uLongf _compressedSize;\n\n    i32 _maxLocationBufferCacheSize;\n    LocationBuffer* _currLocationBuffer;\n    std::queue<LocationBuffer*> _locationCacheQueue;\n    std::map<nString, LocationBuffer*> _locationCache;\n    std::map<nString, LocationBuffer*>::iterator _iterLocationCache;\n\n    ui32 _chunkOffset, _chunkBlockSize; //the file location for the start of the chunk data\n    ui32 _chunkLength, _oldChunkLength; //length of chunk data, old length of chunk data\n    ui32 _locOffset;  //the file location for the start of the location data\n    ui32 _fileSize;\n    bool _isDirtyLocationBuffer;\n    bool _isDone;\n    bool _isThreadFinished;\n    bool _shouldDisableLoading;\n};"
  },
  {
    "path": "SoA/WorldStructs.cpp",
    "content": "#include \"stdafx.h\"\n#include \"WorldStructs.h\"\n\n#include \"BlockData.h\"\n#include \"SoaOptions.h\"\n#include \"GameManager.h\"\n\nMultiplePreciseTimer globalMultiplePreciseTimer; ///< for easy global benchmarking\nAccumulationTimer globalAccumulationTimer; ///< for easy global benchmarking\nAccumulationTimer globalRenderAccumulationTimer; ///< for easy global benchmarking\n\nclass Item *ObjectList[OBJECT_LIST_SIZE];\n\nMarker::Marker(const f64v3 &Pos VORB_UNUSED, nString Name VORB_UNUSED, f32v3 Color VORB_UNUSED) : pos(Pos), dist(0.0), name(Name)\n{\n    // TODO(Ben): implement and remove unused tags\n}\n\nvoid Marker::Draw(f32m4 &VP VORB_UNUSED, const f64v3 &playerPos VORB_UNUSED)\n{\n    // TODO(Ben): implement and remove unused tags\n}\n"
  },
  {
    "path": "SoA/WorldStructs.h",
    "content": "#pragma once\n#include <queue>\n\n#include <Vorb/Timing.h>\n#include <Vorb/graphics/Texture.h>\n\n#include \"Constants.h\"\n#include \"Vertex.h\"\n\nextern MultiplePreciseTimer globalMultiplePreciseTimer; ///< For easy global benchmarking\nextern AccumulationTimer globalAccumulationTimer;\nextern AccumulationTimer globalRenderAccumulationTimer; ///< for easy global benchmarking\n\nextern class Item *ObjectList[OBJECT_LIST_SIZE];\n\nconst int maxParticles = 10000;\n\nstruct PlanetGenData;\n\nclass FixedSizeBillboardVertex{\npublic:\n    f32v3 pos;\n    GLubyte uv[2];\n};\n\n//TODO(Ben): Make this work again\nclass Marker{\npublic:\n    f64v3 pos;\n    ColorRGBA8 color;\n    int num;\n    double dist;\n    nString name;\n\n    vg::Texture distText;\n    vg::Texture nameTex;\n\n    Marker(const f64v3 &Pos, nString Name, const f32v3 Color);\n    void Draw(f32m4 &VP, const f64v3 &playerPos);\n};\n\n//flags\nconst int TOOSTEEP = 0x4;\n\nstruct MineralData\n{\n    MineralData(GLint btype, GLint startheight, float startchance, GLint centerheight, float centerchance, GLint endheight, float endchance, GLint minsize, GLint maxsize)\n    {\n        blockType = btype;\n        startHeight = startheight;\n        startChance = startchance;\n        endHeight = endheight;\n        endChance = endchance;\n        centerHeight = centerheight;\n        centerChance = centerchance;\n        minSize = minsize;\n        maxSize = maxsize;\n    }\n    GLint blockType, startHeight, endHeight, centerHeight, minSize, maxSize;\n    GLfloat startChance, centerChance, endChance;\n};\n\nclass BillboardVertex\n{\npublic:\n    f32v3 pos;\n    f32v2 uvMult;\n    GLubyte texUnit;\n    GLubyte texID;\n    GLubyte light[2];\n    GLubyte color[4];\n    GLubyte size;\n    GLubyte xMod;\n    GLubyte padding[2]; //needs to be 4 byte aligned\n};\n\nclass PhysicsBlockPosLight\n{\npublic:\n    f32v3 pos; //12\n    ColorRGB8 color; //15\n    GLubyte pad1; //16\n    ColorRGB8 overlayColor; //19\n    GLubyte pad2; //20\n    GLubyte light[2]; //22\n    GLubyte pad3[2]; //24\n};\n\nclass TreeVertex\n{\npublic:\n    f32v2 pos; //8\n    f32v3 center; //20\n    GLubyte lr, lg, lb, size; //24\n    GLubyte tr, tg, tb, ltex; //28\n};\n\n//No idea how this works. Something to do with prime numbers, but returns # between -1 and 1\ninline double PseudoRand(int x, int z)\n{\n     int n= (x & 0xFFFF) + ((z & 0x7FFF) << 16);\n     n=(n<<13)^n;\n     int nn=(n*(n*n*60493+z*19990303)+x*1376312589)&0x7fffffff;\n     return 1.0-((double)nn/1073741824.0);\n}\n\n\ninline double PseudoRand(int n)\n{\n    n = (n << 13) ^ n;\n    int nn = (n*(n*n * 60493 + n * 19990303) + n * 1376312589) & 0x7fffffff;\n    return 1.0 - ((double)nn / 1073741824.0);\n}\n\n"
  },
  {
    "path": "SoA/ZipFile.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ZipFile.h\"\n\n#include \"Errors.h\"\n\nZipFile::ZipFile(nString fileName) : _zipFile(NULL), _failure(0) {\n    _zipFile = unzOpen(fileName.c_str());\n    if (_zipFile == NULL) {\n        _failure = 1;\n        return;\n    }\n\n    if (unzGetGlobalInfo(_zipFile, &_globalInfo) != UNZ_OK) {\n        _failure = 1;\n        pError((\"could not read file global info in \" + fileName).c_str());\n        unzClose(_zipFile);\n        return;\n    }\n}\n\nZipFile::~ZipFile() {\n    if (_zipFile != NULL) {\n        unzClose(_zipFile);\n    }\n}\n\nui8* ZipFile::readFile(nString fileName, size_t& fileSize) {\n    // const int READ_SIZE = 8196;\n    const int MAX_FILENAME = 256;\n    const char dir_delimiter = '/';\n\n    unzGoToFirstFile(_zipFile);\n\n    // Loop to extract all files\n    uLong i;\n    for (i = 0; i < _globalInfo.number_entry; ++i) {\n        // Get info about current file.\n        unz_file_info file_info;\n        char filename[MAX_FILENAME];\n        if (unzGetCurrentFileInfo(\n            _zipFile,\n            &file_info,\n            filename,\n            MAX_FILENAME,\n            nullptr, 0, nullptr, 0) != UNZ_OK) {\n            printf(\"could not read file info\\n\");\n            return nullptr;\n        }\n\n        // Check if this entry is a directory or file.\n        const size_t filename_length = strlen(filename);\n        if (filename[filename_length - 1] != dir_delimiter && fileName.size() >= filename_length && fileName == &(filename[filename_length - fileName.size()])) //check that its not a dir and check that it is this file.\n        {\n            unsigned char *buffer = new unsigned char[file_info.uncompressed_size];\n            // Entry is a file, so extract it.\n            printf(\"file:%s\\n\", filename);\n            //    fflush(stdout);\n            if (unzOpenCurrentFile(_zipFile) != UNZ_OK) {\n                delete[] buffer;\n                printf(\"could not open file\\n\");\n                return nullptr;\n            }\n\n            int error = UNZ_OK;\n\n            error = unzReadCurrentFile(_zipFile, buffer, file_info.uncompressed_size);\n            if (error < 0) {\n                printf(\"error %d\\n\", error);\n                unzCloseCurrentFile(_zipFile);\n                delete[] buffer;\n                return nullptr;\n            }\n            fileSize = file_info.uncompressed_size;\n            return buffer;\n        }\n\n        unzCloseCurrentFile(_zipFile);\n\n        // Go the the next entry listed in the zip file.\n        if ((i + 1) < _globalInfo.number_entry) {\n            if (unzGoToNextFile(_zipFile) != UNZ_OK) {\n                printf(\"could not read next file\\n\");\n                return nullptr;\n            }\n        }\n    }\n    return nullptr;\n}"
  },
  {
    "path": "SoA/ZipFile.h",
    "content": "#pragma once\n\n#include <minizip/unzip.h>\n#include <Vorb/types.h>\n\nclass ZipFile {\npublic:\n    ZipFile(nString fileName);\n    ~ZipFile();\n\n    ui8* readFile(nString fileName, size_t& fileSize);\n    bool isFailure() {\n        return _failure;\n    }\nprivate:\n    unzFile _zipFile;\n    unz_global_info _globalInfo;\n    bool _failure;\n};\n"
  },
  {
    "path": "SoA/app.config",
    "content": "GraphicsCore: false\nGraphicsMajor: 3\nGraphicsMinor: 2\nIsBorderless: false\nIsFullscreen: false\nMaxFPS: 60\nScreenHeight: 600\nScreenWidth: 800\nSwapInterval: VSync\n"
  },
  {
    "path": "SoA/atomicops.h",
    "content": "// �2013 Cameron Desrochers.\n// Distributed under the simplified BSD license \n\n/*\n\nCopyright (c) 2013, Cameron Desrochers\nMIT License.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n*/\n\n#pragma once\n\n// Provides portable (VC++2010+, Intel ICC 13, GCC 4.7+, and anything C++11 compliant) implementation\n// of low-level memory barriers, plus a few semi-portable utility macros (for inlining and alignment).\n// Also has a basic atomic type (limited to hardware-supported atomics with no memory ordering guarantees).\n// Uses the AE_* prefix for macros (historical reasons), and the \"moodycamel\" namespace for symbols.\n\n#include <cassert>\n\n\n// Platform detection\n#if defined(__INTEL_COMPILER)\n#define AE_ICC\n#elif defined(_MSC_VER)\n#define AE_VCPP\n#elif defined(__GNUC__)\n#define AE_GCC\n#endif\n\n#if defined(_M_IA64) || defined(__ia64__)\n#define AE_ARCH_IA64\n#elif defined(_WIN64) || defined(__amd64__) || defined(_M_X64) || defined(__x86_64__)\n#define AE_ARCH_X64\n#elif defined(_M_IX86) || defined(__i386__)\n#define AE_ARCH_X86\n#elif defined(_M_PPC) || defined(__powerpc__)\n#define AE_ARCH_PPC\n#else\n#define AE_ARCH_UNKNOWN\n#endif\n\n\n// AE_UNUSED\n#define AE_UNUSED(x) ((void)x)\n\n\n// AE_FORCEINLINE\n#if defined(AE_VCPP) || defined(AE_ICC)\n#define AE_FORCEINLINE __forceinline\n#elif defined(AE_GCC)\n//#define AE_FORCEINLINE __attribute__((always_inline)) \n#define AE_FORCEINLINE inline\n#else\n#define AE_FORCEINLINE inline\n#endif\n\n\n// AE_ALIGN\n#if defined(AE_VCPP) || defined(AE_ICC)\n#define AE_ALIGN(x) __declspec(align(x))\n#elif defined(AE_GCC)\n#define AE_ALIGN(x) __attribute__((aligned(x)))\n#else\n// Assume GCC compliant syntax...\n#define AE_ALIGN(x) __attribute__((aligned(x)))\n#endif\n\n\n// Portable atomic fences implemented below:\n\nnamespace moodycamel {\n\n    enum memory_order {\n        memory_order_relaxed,\n        memory_order_acquire,\n        memory_order_release,\n        memory_order_acq_rel,\n        memory_order_seq_cst,\n\n        // memory_order_sync: Forces a full sync:\n        // #LoadLoad, #LoadStore, #StoreStore, and most significantly, #StoreLoad\n        memory_order_sync = memory_order_seq_cst\n    };\n\n}    // end namespace moodycamel\n\n#if defined(AE_VCPP) || defined(AE_ICC)\n// VS2010 and ICC13 don't support std::atomic_*_fence, implement our own fences\n\n#include <intrin.h>\n\n#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)\n#define AeFullSync _mm_mfence\n#define AeLiteSync _mm_mfence\n#elif defined(AE_ARCH_IA64)\n#define AeFullSync __mf\n#define AeLiteSync __mf\n#elif defined(AE_ARCH_PPC)\n#include <ppcintrinsics.h>\n#define AeFullSync __sync\n#define AeLiteSync __lwsync\n#endif\n\n\n#ifdef AE_VCPP\n#pragma warning(push)\n#pragma warning(disable: 4365)        // Disable erroneous 'conversion from long to unsigned int, signed/unsigned mismatch' error when using `assert`\n#endif\n\nnamespace moodycamel {\n\n    AE_FORCEINLINE void compiler_fence(memory_order order)\n    {\n        switch (order) {\n        case memory_order_relaxed: break;\n        case memory_order_acquire: _ReadBarrier(); break;\n        case memory_order_release: _WriteBarrier(); break;\n        case memory_order_acq_rel: _ReadWriteBarrier(); break;\n        case memory_order_seq_cst: _ReadWriteBarrier(); break;\n        default: assert(false);\n        }\n    }\n\n    // x86/x64 have a strong memory model -- all loads and stores have\n    // acquire and release semantics automatically (so only need compiler\n    // barriers for those).\n#if defined(AE_ARCH_X86) || defined(AE_ARCH_X64)\n    AE_FORCEINLINE void fence(memory_order order)\n    {\n        switch (order) {\n        case memory_order_relaxed: break;\n        case memory_order_acquire: _ReadBarrier(); break;\n        case memory_order_release: _WriteBarrier(); break;\n        case memory_order_acq_rel: _ReadWriteBarrier(); break;\n        case memory_order_seq_cst:\n            _ReadWriteBarrier();\n            AeFullSync();\n            _ReadWriteBarrier();\n            break;\n        default: assert(false);\n        }\n    }\n#else\n    AE_FORCEINLINE void fence(memory_order order)\n    {\n        // Non-specialized arch, use heavier memory barriers everywhere just in case :-(\n        switch (order) {\n        case memory_order_relaxed:\n            break;\n        case memory_order_acquire:\n            _ReadBarrier();\n            AeLiteSync();\n            _ReadBarrier();\n            break;\n        case memory_order_release:\n            _WriteBarrier();\n            AeLiteSync();\n            _WriteBarrier();\n            break;\n        case memory_order_acq_rel:\n            _ReadWriteBarrier();\n            AeLiteSync();\n            _ReadWriteBarrier();\n            break;\n        case memory_order_seq_cst:\n            _ReadWriteBarrier();\n            AeFullSync();\n            _ReadWriteBarrier();\n            break;\n        default: assert(false);\n        }\n    }\n#endif\n}    // end namespace moodycamel\n#else\n// Use standard library of atomics\n#include <atomic>\n\nnamespace moodycamel {\n\n    AE_FORCEINLINE void compiler_fence(memory_order order)\n    {\n        switch (order) {\n        case memory_order_relaxed: break;\n        case memory_order_acquire: std::atomic_signal_fence(std::memory_order_acquire); break;\n        case memory_order_release: std::atomic_signal_fence(std::memory_order_release); break;\n        case memory_order_acq_rel: std::atomic_signal_fence(std::memory_order_acq_rel); break;\n        case memory_order_seq_cst: std::atomic_signal_fence(std::memory_order_seq_cst); break;\n        default: assert(false);\n        }\n    }\n\n    AE_FORCEINLINE void fence(memory_order order)\n    {\n        switch (order) {\n        case memory_order_relaxed: break;\n        case memory_order_acquire: std::atomic_thread_fence(std::memory_order_acquire); break;\n        case memory_order_release: std::atomic_thread_fence(std::memory_order_release); break;\n        case memory_order_acq_rel: std::atomic_thread_fence(std::memory_order_acq_rel); break;\n        case memory_order_seq_cst: std::atomic_thread_fence(std::memory_order_seq_cst); break;\n        default: assert(false);\n        }\n    }\n\n}    // end namespace moodycamel\n\n#endif\n\n\n\n\n#if !defined(AE_VCPP) || _MSC_VER >= 1700\n#define AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC\n#endif\n\n#ifdef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC\n#include <atomic>\n#endif\n#include <utility>\n\n// WARNING: *NOT* A REPLACEMENT FOR std::atomic. READ CAREFULLY:\n// Provides basic support for atomic variables -- no memory ordering guarantees are provided.\n// The guarantee of atomicity is only made for types that already have atomic load and store guarantees\n// at the hardware level -- on most platforms this generally means aligned pointers and integers (only).\nnamespace moodycamel {\n    template<typename T>\n    class weak_atomic\n    {\n    public:\n        weak_atomic() { }\n#ifdef AE_VCPP\n#pragma warning(disable: 4100)        // Get rid of (erroneous) 'unreferenced formal parameter' warning\n#endif\n        template<typename U> weak_atomic(U&& x) : value(std::forward<U>(x)) {  }\n        weak_atomic(weak_atomic const& other) : value(other.value) {  }\n        weak_atomic(weak_atomic&& other) : value(std::move(other.value)) {  }\n#ifdef AE_VCPP\n#pragma warning(default: 4100)\n#endif\n\n        AE_FORCEINLINE operator T() const { return load(); }\n\n\n#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC\n        template<typename U> AE_FORCEINLINE weak_atomic const& operator=(U&& x) { value = std::forward<U>(x); return *this; }\n        AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) { value = other.value; return *this; }\n\n        AE_FORCEINLINE T load() const { return value; }\n#else\n        template<typename U>\n        AE_FORCEINLINE weak_atomic const& operator=(U&& x)\n        {\n            value.store(std::forward<U>(x), std::memory_order_relaxed);\n            return *this;\n        }\n\n        AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other)\n        {\n            value.store(other.value.load(std::memory_order_relaxed), std::memory_order_relaxed);\n            return *this;\n        }\n\n        AE_FORCEINLINE T load() const { return value.load(std::memory_order_relaxed); }\n#endif\n\n\n    private:\n#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC\n        // No std::atomic support, but still need to circumvent compiler optimizations.\n        // `volatile` will make memory access slow, but is guaranteed to be reliable.\n        volatile T value;\n#else\n        std::atomic<T> value;\n#endif\n    };\n\n}    // end namespace moodycamel\n\n\n#ifdef AE_VCPP\n#pragma warning(pop)\n#endif\n"
  },
  {
    "path": "SoA/errorlog.txt",
    "content": "*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n*ERROR: FMOD error! (23) File not found. \n \n"
  },
  {
    "path": "SoA/main.cpp",
    "content": "#include \"stdafx.h\"\n\n#ifdef VORB_OS_WINDOWS\n#include <SDL/SDL_syswm.h>\n#endif\n#include <Vorb/Vorb.h>\n//#define VORB_IMPL_UI_SDL\n//#define VORB_IMPL_SOUND_FMOD\n//#define VORB_IMPL_FONT_SDL\n#include <Vorb/VorbLibs.h>\n#include <Vorb/script/lua/Environment.h>\n\n#include \"App.h\"\n#include \"Startup.h\"\n#include \"ConsoleMain.h\"\n\n// Entry\nint main(int argc, char **argv) {\n    // Initialize Vorb modules\n    vorb::init(vorb::InitParam::ALL);\n\n#ifdef VORB_OS_WINDOWS\n    // Tell windows that our priority class should be above normal\n    SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);\n#endif\n\n    // Get the startup mode\n    switch (startup(argc, argv)) {\n    case Startup::APP:\n        // Run the game\n        { App().run(); }\n        break;\n    case Startup::CONSOLE:\n        // Run the console\n        consoleMain<vscript::lua::Environment>();\n        break;\n    case Startup::HELP:\n        // Pause on user input\n        getchar();\n        break;\n    default:\n        // Do nothing\n        break;\n    }\n\n    // Dispose Vorb modules\n    vorb::dispose(vorb::InitParam::ALL);\n\n#ifdef VORB_OS_WINDOWS\n    // Need to free the console on windows\n    FreeConsole();\n#endif\n\n    return 0;\n}\n"
  },
  {
    "path": "SoA/qef.cpp",
    "content": "/*\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\n* distribute this software, either in source code form or as a compiled\n* binary, for any purpose, commercial or non-commercial, and by any\n* means.\n*\n* In jurisdictions that recognize copyright laws, the author or authors\n* of this software dedicate any and all copyright interest in the\n* software to the public domain. We make this dedication for the benefit\n* of the public at large and to the detriment of our heirs and\n* successors. We intend this dedication to be an overt act of\n* relinquishment in perpetuity of all present and future rights to this\n* software under copyright law.\n*\n* THE SOFTWARE IS 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR\n* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n* OTHER DEALINGS IN THE SOFTWARE.\n*\n* For more information, please refer to <http://unlicense.org/>\n*/\n#include \"stdafx.h\"\n#include \"qef.h\"\n#include <stdexcept>\nnamespace svd {\n\n    QefData::QefData() {\n        this->clear();\n    }\n\n    QefData::QefData(const float ata_00, const float ata_01,\n                     const float ata_02, const float ata_11, const float ata_12,\n                     const float ata_22, const float atb_x, const float atb_y,\n                     const float atb_z, const float btb, const float massPoint_x,\n                     const float massPoint_y, const float massPoint_z,\n                     const int numPoints) {\n        this->set(ata_00, ata_01, ata_02, ata_11, ata_12, ata_22, atb_x, atb_y,\n                  atb_z, btb, massPoint_x, massPoint_y, massPoint_z, numPoints);\n    }\n\n    QefData::QefData(const QefData &rhs) {\n        this->set(rhs);\n    }\n\n    QefData& QefData::operator=(const QefData& rhs) {\n        this->set(rhs);\n        return *this;\n    }\n\n    void QefData::add(const QefData &rhs) {\n        this->ata_00 += rhs.ata_00;\n        this->ata_01 += rhs.ata_01;\n        this->ata_02 += rhs.ata_02;\n        this->ata_11 += rhs.ata_11;\n        this->ata_12 += rhs.ata_12;\n        this->ata_22 += rhs.ata_22;\n        this->atb_x += rhs.atb_x;\n        this->atb_y += rhs.atb_y;\n        this->atb_z += rhs.atb_z;\n        this->btb += rhs.btb;\n        this->massPoint_x += rhs.massPoint_x;\n        this->massPoint_y += rhs.massPoint_y;\n        this->massPoint_z += rhs.massPoint_z;\n        this->numPoints += rhs.numPoints;\n    }\n\n    void QefData::clear() {\n        this->set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n    }\n\n    void QefData::set(const float ata_00, const float ata_01,\n                      const float ata_02, const float ata_11, const float ata_12,\n                      const float ata_22, const float atb_x, const float atb_y,\n                      const float atb_z, const float btb, const float massPoint_x,\n                      const float massPoint_y, const float massPoint_z,\n                      const int numPoints) {\n        this->ata_00 = ata_00;\n        this->ata_01 = ata_01;\n        this->ata_02 = ata_02;\n        this->ata_11 = ata_11;\n        this->ata_12 = ata_12;\n        this->ata_22 = ata_22;\n        this->atb_x = atb_x;\n        this->atb_y = atb_y;\n        this->atb_z = atb_z;\n        this->btb = btb;\n        this->massPoint_x = massPoint_x;\n        this->massPoint_y = massPoint_y;\n        this->massPoint_z = massPoint_z;\n        this->numPoints = numPoints;\n    }\n\n    void QefData::set(const QefData &rhs) {\n        this->set(rhs.ata_00, rhs.ata_01, rhs.ata_02, rhs.ata_11, rhs.ata_12,\n                  rhs.ata_22, rhs.atb_x, rhs.atb_y, rhs.atb_z, rhs.btb,\n                  rhs.massPoint_x, rhs.massPoint_y, rhs.massPoint_z,\n                  rhs.numPoints);\n    }\n\n#ifndef NO_OSTREAM\n    std::ostream &operator<<(std::ostream &os, const QefData &qef) {\n        SMat3 ata;\n        Vec3 atb, mp;\n        ata.setSymmetric(qef.ata_00, qef.ata_01, qef.ata_02, qef.ata_11,\n                         qef.ata_12, qef.ata_22);\n        atb.set(qef.atb_x, qef.atb_y, qef.atb_z);\n        mp.set(qef.massPoint_x, qef.massPoint_y, qef.massPoint_z);\n\n        if (qef.numPoints > 0) {\n            VecUtils::scale(mp, 1.0f / qef.numPoints);\n        }\n\n        os << \"QefData [ \" << std::endl\n            << \" ata =\" << std::endl << ata << \",\" << std::endl\n            << \" atb = \" << atb << \",\" << std::endl\n            << \" btb = \" << qef.btb << \",\" << std::endl\n            << \" massPoint = \" << mp << \",\" << std::endl\n            << \" numPoints = \" << qef.numPoints << \"]\";\n        return os;\n    }\n#endif\n\n    QefSolver::QefSolver() : data(), ata(), atb(), massPoint(), x(),\n        hasSolution(false) {\n    }\n\n    static void normalize(float &nx, float &ny, float &nz) {\n        Vec3 tmpv(nx, ny, nz);\n        VecUtils::normalize(tmpv);\n        nx = tmpv.x;\n        ny = tmpv.y;\n        nz = tmpv.z;\n    }\n\n    void QefSolver::add(const float px, const float py, const float pz,\n                        float nx, float ny, float nz) {\n        this->hasSolution = false;\n        normalize(nx, ny, nz);\n        this->data.ata_00 += nx * nx;\n        this->data.ata_01 += nx * ny;\n        this->data.ata_02 += nx * nz;\n        this->data.ata_11 += ny * ny;\n        this->data.ata_12 += ny * nz;\n        this->data.ata_22 += nz * nz;\n        const float dot = nx * px + ny * py + nz * pz;\n        this->data.atb_x += dot * nx;\n        this->data.atb_y += dot * ny;\n        this->data.atb_z += dot * nz;\n        this->data.btb += dot * dot;\n        this->data.massPoint_x += px;\n        this->data.massPoint_y += py;\n        this->data.massPoint_z += pz;\n        ++this->data.numPoints;\n    }\n\n    void QefSolver::add(const Vec3 &p, const Vec3 &n) {\n        this->add(p.x, p.y, p.z, n.x, n.y, n.z);\n    }\n\n    void QefSolver::add(const QefData &rhs) {\n        this->hasSolution = false;\n        this->data.add(rhs);\n    }\n\n    QefData QefSolver::getData() {\n        return data;\n    }\n\n    float QefSolver::getError() {\n        if (!this->hasSolution) {\n            throw std::runtime_error(\"illegal state\");\n        }\n\n        return this->getError(this->x);\n    }\n\n    float QefSolver::getError(const Vec3 &pos) {\n        if (!this->hasSolution) {\n            this->setAta();\n            this->setAtb();\n        }\n\n        Vec3 atax;\n        MatUtils::vmul_symmetric(atax, this->ata, pos);\n        return VecUtils::dot(pos, atax) - 2 * VecUtils::dot(pos, this->atb)\n            + this->data.btb;\n    }\n\n    void QefSolver::reset() {\n        this->hasSolution = false;\n        this->data.clear();\n    }\n\n    void QefSolver::setAta() {\n        this->ata.setSymmetric(this->data.ata_00, this->data.ata_01,\n                               this->data.ata_02, this->data.ata_11, this->data.ata_12,\n                               this->data.ata_22);\n    }\n\n    void QefSolver::setAtb() {\n        this->atb.set(this->data.atb_x, this->data.atb_y, this->data.atb_z);\n    }\n\n    float QefSolver::solve(Vec3 &outx, const float svd_tol,\n                           const int svd_sweeps, const float pinv_tol) {\n        if (this->data.numPoints == 0) {\n            throw std::invalid_argument(\"...\");\n        }\n\n        this->massPoint.set(this->data.massPoint_x, this->data.massPoint_y,\n                            this->data.massPoint_z);\n        VecUtils::scale(this->massPoint, 1.0f / this->data.numPoints);\n        this->setAta();\n        this->setAtb();\n        Vec3 tmpv;\n        MatUtils::vmul_symmetric(tmpv, this->ata, this->massPoint);\n        VecUtils::sub(this->atb, this->atb, tmpv);\n        this->x.clear();\n        const float result = Svd::solveSymmetric(this->ata, this->atb,\n                                                 this->x, svd_tol, svd_sweeps, pinv_tol);\n        VecUtils::addScaled(this->x, 1, this->massPoint);\n        this->setAtb();\n        outx.set(x);\n        this->hasSolution = true;\n        return result;\n    }\n}"
  },
  {
    "path": "SoA/qef.h",
    "content": "/*\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\n* distribute this software, either in source code form or as a compiled\n* binary, for any purpose, commercial or non-commercial, and by any\n* means.\n*\n* In jurisdictions that recognize copyright laws, the author or authors\n* of this software dedicate any and all copyright interest in the\n* software to the public domain. We make this dedication for the benefit\n* of the public at large and to the detriment of our heirs and\n* successors. We intend this dedication to be an overt act of\n* relinquishment in perpetuity of all present and future rights to this\n* software under copyright law.\n*\n* THE SOFTWARE IS 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR\n* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n* OTHER DEALINGS IN THE SOFTWARE.\n*\n* For more information, please refer to <http://unlicense.org/>\n*/\n#ifndef QEF_H\n#define QEF_H\n#ifndef NO_OSTREAM\n#include <iostream>\n#endif\n\n#include \"svd.h\"\nnamespace svd {\n    class QefData {\n    public:\n        float ata_00, ata_01, ata_02, ata_11, ata_12, ata_22;\n        float atb_x, atb_y, atb_z;\n        float btb;\n        float massPoint_x, massPoint_y, massPoint_z;\n        int numPoints;\n\n        QefData();\n\n        QefData(const float ata_00, const float ata_01,\n                const float ata_02, const float ata_11, const float ata_12,\n                const float ata_22, const float atb_x, const float atb_y,\n                const float atb_z, const float btb, const float massPoint_x,\n                const float massPoint_y, const float massPoint_z,\n                const int numPoints);\n\n        void add(const QefData &rhs);\n\n        void clear();\n\n        void set(const float ata_00, const float ata_01,\n                 const float ata_02, const float ata_11, const float ata_12,\n                 const float ata_22, const float atb_x, const float atb_y,\n                 const float atb_z, const float btb, const float massPoint_x,\n                 const float massPoint_y, const float massPoint_z,\n                 const int numPoints);\n\n        void set(const QefData &rhs);\n\n        QefData(const QefData &rhs);\n        QefData &operator= (const QefData &rhs);\n    };\n#ifndef NO_OSTREAM\n    std::ostream &operator<<(std::ostream &os, const QefData &d);\n#endif\n    class QefSolver {\n    private:\n        QefData data;\n        SMat3 ata;\n        Vec3 atb, massPoint, x;\n        bool hasSolution;\n    public:\n        QefSolver();\n    public:\n\n        const Vec3& getMassPoint() const { return massPoint; }\n\n        void add(const float px, const float py, const float pz,\n                 float nx, float ny, float nz);\n        void add(const Vec3 &p, const Vec3 &n);\n        void add(const QefData &rhs);\n        QefData getData();\n        float getError();\n        float getError(const Vec3 &pos);\n        void reset();\n        float solve(Vec3 &outx, const float svd_tol,\n                    const int svd_sweeps, const float pinv_tol);\n    private:\n        QefSolver(const QefSolver &rhs);\n        QefSolver &operator=(const QefSolver &rhs);\n        void setAta();\n        void setAtb();\n    };\n};\n#endif"
  },
  {
    "path": "SoA/readerwriterqueue.h",
    "content": "// �2013 Cameron Desrochers.\n// Distributed under the simplified BSD license \n\n/*\n\nCopyright (c) 2013, Cameron Desrochers\nMIT License.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n*/\n\n#pragma once\n#include \"atomicops.h\"\n#include <type_traits>\n#include <utility>\n#include <cassert>\n#include <stdexcept>\n#include <cstdint>\n#include <cstdlib> // For malloc/free & size_t\n\n\n// A lock-free queue for a single-consumer, single-producer architecture.\n// The queue is also wait-free in the common path (except if more memory\n// needs to be allocated, in which case malloc is called).\n// Allocates memory sparingly (O(lg(n) times, amortized), and only once if\n// the original maximum size estimate is never exceeded.\n// Tested on x86/x64 processors, but semantics should be correct for all\n// architectures (given the right implementations in atomicops.h), provided\n// that aligned integer and pointer accesses are naturally atomic.\n// Note that there should only be one consumer thread and producer thread;\n// Switching roles of the threads, or using multiple consecutive threads for\n// one role, is not safe unless properly synchronized.\n// Using the queue exclusively from one thread is fine, though a bit silly.\n\n#define CACHE_LINE_SIZE 64\n\n#ifdef AE_VCPP\n#pragma warning(push)\n#pragma warning(disable: 4324) // classure was padded due to __declspec(align())\n#pragma warning(disable: 4820) // padding was added\n#pragma warning(disable: 4127) // conditional expression is constant\n#endif\n\nnamespace moodycamel {\n    template<typename T>\n    class ReaderWriterQueue {\n        // Design: Based on a queue-of-queues. The low-level queues are just\n        // circular buffers with front and tail indices indicating where the\n        // next element to dequeue is and where the next element can be enqueued,\n        // respectively. Each low-level queue is called a \"block\". Each block\n        // wastes exactly one element's worth of space to keep the design simple\n        // (if front == tail then the queue is empty, and can't be full).\n        // The high-level queue is a circular linked list of blocks; again there\n        // is a front and tail, but this time they are pointers to the blocks.\n        // The front block is where the next element to be dequeued is, provided\n        // the block is not empty. The back block is where elements are to be\n        // enqueued, provided the block is not full.\n        // The producer thread owns all the tail indices/pointers. The consumer\n        // thread owns all the front indices/pointers. Both threads read each\n        // other's variables, but only the owning thread updates them. E.g. After\n        // the consumer reads the producer's tail, the tail may change before the\n        // consumer is done dequeuing an object, but the consumer knows the tail\n        // will never go backwards, only forwards.\n        // If there is no room to enqueue an object, an additional block (of\n        // greater size than the last block) is added. Blocks are never removed.\n\n    public:\n        // Constructs a queue that can hold maxSize elements without further\n        // allocations. Allocates maxSize + 1, rounded up to the nearest power\n        // of 2, elements.\n        explicit ReaderWriterQueue(size_t maxSize = 15)\n            : largestBlockSize(ceilToPow2(maxSize + 1))    // We need a spare slot to fit maxSize elements in the block\n#ifndef NDEBUG\n            , enqueuing(false)\n            , dequeuing(false)\n#endif\n        {\n            assert(maxSize > 0);\n\n            auto firstBlock = new Block(largestBlockSize);\n            firstBlock->next = firstBlock;\n\n            frontBlock = firstBlock;\n            tailBlock = firstBlock;\n\n            // Make sure the reader/writer threads will have the initialized memory setup above:\n            fence(memory_order_sync);\n        }\n\n        // Note: The queue should not be accessed concurrently while it's\n        // being deleted. It's up to the user to synchronize this.\n        ~ReaderWriterQueue() {\n            // Make sure we get the latest version of all variables from other CPUs:\n            fence(memory_order_sync);\n\n            // Destroy any remaining objects in queue and free memory\n            Block* tailBlock_ = tailBlock;\n            Block* block = frontBlock;\n            do {\n                Block* nextBlock = block->next;\n                size_t blockFront = block->front;\n                size_t blockTail = block->tail;\n\n                for (size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask()) {\n                    auto element = reinterpret_cast<T*>(block->data + i * sizeof(T));\n                    element->~T();\n                    (void)element;\n                }\n\n                delete block;\n                block = nextBlock;\n\n            } while (block != tailBlock_);\n        }\n\n        // Enqueues a copy of element if there is room in the queue.\n        // Returns true if the element was enqueued, false otherwise.\n        // Does not allocate memory.\n        AE_FORCEINLINE bool try_enqueue(T const& element) {\n            return inner_enqueue<CannotAlloc>(element);\n        }\n        // Enqueues a moved copy of element if there is room in the queue.\n        // Returns true if the element was enqueued, false otherwise.\n        // Does not allocate memory.\n        AE_FORCEINLINE bool try_enqueue(T&& element) {\n            return inner_enqueue<CannotAlloc>(std::forward<T>(element));\n        }\n        // Enqueues a copy of element on the queue.\n        // Allocates an additional block of memory if needed.\n        AE_FORCEINLINE void enqueue(T const& element) {\n            inner_enqueue<CanAlloc>(element);\n        }\n        // Enqueues a moved copy of element on the queue.\n        // Allocates an additional block of memory if needed.\n        AE_FORCEINLINE void enqueue(T&& element) {\n            inner_enqueue<CanAlloc>(std::forward<T>(element));\n        }\n\n\n        // Attempts to dequeue an element; if the queue is empty,\n        // returns false instead. If the queue has at least one element,\n        // moves front to result using operator=, then returns true.\n        bool try_dequeue(T& result) {\n#ifndef NDEBUG\n            ReentrantGuard guard(this->dequeuing);\n#endif\n\n            // High-level pseudocode:\n            // Remember where the tail block is\n            // If the front block has an element in it, dequeue it\n            // Else\n            // If front block was the tail block when we entered the function, return false\n            // Else advance to next block and dequeue the item there\n\n            // Note that we have to use the value of the tail block from before we check if the front\n            // block is full or not, in case the front block is empty and then, before we check if the\n            // tail block is at the front block or not, the producer fills up the front block *and\n            // moves on*, which would make us skip a filled block. Seems unlikely, but was consistently\n            // reproducible in practice.\n            Block* tailBlockAtStart = tailBlock;\n            fence(memory_order_acquire);\n\n            Block* frontBlock_ = frontBlock.load();\n            size_t blockTail = frontBlock_->tail.load();\n            size_t blockFront = frontBlock_->front.load();\n            fence(memory_order_acquire);\n\n            if (blockFront != blockTail) {\n                // Front block not empty, dequeue from here\n                auto element = reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));\n                result = std::move(*element);\n                element->~T();\n\n                blockFront = (blockFront + 1) & frontBlock_->sizeMask();\n\n                fence(memory_order_release);\n                frontBlock_->front = blockFront;\n            } else if (frontBlock_ != tailBlockAtStart) {\n                // Front block is empty but there's another block ahead, advance to it\n                Block* nextBlock = frontBlock_->next;\n                // Don't need an acquire fence here since next can only ever be set on the tailBlock,\n                // and we're not the tailBlock, and we did an acquire earlier after reading tailBlock which\n                // ensures next is up-to-date on this CPU in case we recently were at tailBlock.\n\n                size_t nextBlockFront = nextBlock->front.load();\n                size_t nextBlockTail = nextBlock->tail;\n                fence(memory_order_acquire);\n\n                // Since the tailBlock is only ever advanced after being written to,\n                // we know there's for sure an element to dequeue on it\n                assert(nextBlockFront != nextBlockTail);\n                AE_UNUSED(nextBlockTail);\n\n                // We're done with this block, let the producer use it if it needs\n                fence(memory_order_release);    // Expose possibly pending changes to frontBlock->front from last dequeue\n                frontBlock = frontBlock_ = nextBlock;\n\n                compiler_fence(memory_order_release);    // Not strictly needed\n\n                auto element = reinterpret_cast<T*>(frontBlock_->data + nextBlockFront * sizeof(T));\n\n                result = std::move(*element);\n                element->~T();\n\n                nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask();\n\n                fence(memory_order_release);\n                frontBlock_->front = nextBlockFront;\n            } else {\n                // No elements in current block and no other block to advance to\n                return false;\n            }\n\n            return true;\n        }\n        // Returns a pointer to the first element in the queue (the one that\n        // would be removed next by a call to `try_dequeue`). If the queue appears\n        // empty at the time the method is called, nullptr is returned instead.\n        // Must be called only from the consumer thread.\n        T* peek() {\n#ifndef NDEBUG\n            ReentrantGuard guard(this->dequeuing);\n#endif\n            // See try_dequeue() for reasoning\n\n            Block* tailBlockAtStart = tailBlock;\n            fence(memory_order_acquire);\n\n            Block* frontBlock_ = frontBlock.load();\n            size_t blockTail = frontBlock_->tail.load();\n            size_t blockFront = frontBlock_->front.load();\n            fence(memory_order_acquire);\n\n            if (blockFront != blockTail) {\n                return reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));\n            } else if (frontBlock_ != tailBlockAtStart) {\n                Block* nextBlock = frontBlock_->next;\n\n                size_t nextBlockFront = nextBlock->front.load();\n                fence(memory_order_acquire);\n\n                assert(nextBlockFront != nextBlock->tail);\n                return reinterpret_cast<T*>(nextBlock->data + nextBlockFront * sizeof(T));\n            }\n            return nullptr;\n        }\n    private:\n        enum AllocationMode {\n            CanAlloc, CannotAlloc\n        };\n\n        template<AllocationMode canAlloc, typename U>\n        bool inner_enqueue(U&& element) {\n#ifndef NDEBUG\n            ReentrantGuard guard(this->enqueuing);\n#endif\n\n            // High-level pseudocode (assuming we're allowed to alloc a new block):\n            // If room in tail block, add to tail\n            // Else check next block\n            // If next block is not the head block, enqueue on next block\n            // Else create a new block and enqueue there\n            // Advance tail to the block we just enqueued to\n\n            Block* tailBlock_ = tailBlock.load();\n            size_t blockFront = tailBlock_->front.load();\n            size_t blockTail = tailBlock_->tail.load();\n            fence(memory_order_acquire);\n\n            size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask();\n            if (nextBlockTail != blockFront) {\n                // This block has room for at least one more element\n                char* location = tailBlock_->data + blockTail * sizeof(T);\n#define new new\n                new (location)T(std::forward<U>(element));\n\n                fence(memory_order_release);\n                tailBlock_->tail = nextBlockTail;\n            } else if (tailBlock_->next.load() != frontBlock) {\n                // Note that the reason we can't advance to the frontBlock and start adding new entries there\n                // is because if we did, then dequeue would stay in that block, eventually reading the new values,\n                // instead of advancing to the next full block (whose values were enqueued first and so should be\n                // consumed first).\n\n                fence(memory_order_acquire);    // Ensure we get latest writes if we got the latest frontBlock\n\n                // tailBlock is full, but there's a free block ahead, use it\n                Block* tailBlockNext = tailBlock_->next.load();\n                size_t nextBlockFront = tailBlockNext->front.load();\n                nextBlockTail = tailBlockNext->tail.load();\n                fence(memory_order_acquire);\n\n                // This block must be empty since it's not the head block and we\n                // go through the blocks in a circle\n                assert(nextBlockFront == nextBlockTail);\n                AE_UNUSED(nextBlockFront);\n\n                char* location = tailBlockNext->data + nextBlockTail * sizeof(T);\n                new (location)T(std::forward<U>(element));\n\n                tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask();\n\n                fence(memory_order_release);\n                tailBlock = tailBlockNext;\n            } else if (canAlloc == CanAlloc) {\n                // tailBlock is full and there's no free block ahead; create a new block\n                largestBlockSize *= 2;\n                Block* newBlock = new Block(largestBlockSize);\n\n                new (newBlock->data) T(std::forward<U>(element));\n\n                assert(newBlock->front == 0);\n                newBlock->tail = 1;\n\n                newBlock->next = tailBlock_->next.load();\n                tailBlock_->next = newBlock;\n\n                // Might be possible for the dequeue thread to see the new tailBlock->next\n                // *without* seeing the new tailBlock value, but this is OK since it can't\n                // advance to the next block until tailBlock is set anyway (because the only\n                // case where it could try to read the next is if it's already at the tailBlock,\n                // and it won't advance past tailBlock in any circumstance).\n\n                fence(memory_order_release);\n                tailBlock = newBlock;\n            } else if (canAlloc == CannotAlloc) {\n                // Would have had to allocate a new block to enqueue, but not allowed\n                return false;\n            } else {\n                assert(false && \"Should be unreachable code\");\n                return false;\n            }\n\n            return true;\n        }\n\n        // Disable copying\n        ReaderWriterQueue(ReaderWriterQueue const&) {}\n\n        // Disable assignment\n        ReaderWriterQueue& operator=(ReaderWriterQueue const&) {}\n\n\n\n        AE_FORCEINLINE static size_t ceilToPow2(size_t x) {\n            // From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2\n            --x;\n            x |= x >> 1;\n            x |= x >> 2;\n            x |= x >> 4;\n            for (size_t i = 1; i < sizeof(size_t); i <<= 1) {\n                x |= x >> (i << 3);\n            }\n            ++x;\n            return x;\n        }\n    private:\n#ifndef NDEBUG\n        struct ReentrantGuard {\n            ReentrantGuard(bool& _inSection)\n            : inSection(_inSection) {\n                assert(!inSection);\n                if (inSection) {\n                    throw std::runtime_error(\"ReaderWriterQueue does not support enqueuing or dequeuing elements from other elements' ctors and dtors\");\n                }\n\n                inSection = true;\n            }\n\n            ~ReentrantGuard() {\n                inSection = false;\n            }\n\n        private:\n            ReentrantGuard& operator=(ReentrantGuard const&);\n\n        private:\n            bool& inSection;\n        };\n#endif\n\n        struct Block {\n            // Avoid false-sharing by putting highly contended variables on their own cache lines\n            AE_ALIGN(CACHE_LINE_SIZE)\n            weak_atomic<size_t> front;    // (Atomic) Elements are read from here\n\n            AE_ALIGN(CACHE_LINE_SIZE)\n                weak_atomic<size_t> tail;    // (Atomic) Elements are enqueued here\n\n            AE_ALIGN(CACHE_LINE_SIZE)    // next isn't very contended, but we don't want it on the same cache line as tail (which is)\n                weak_atomic<Block*> next;    // (Atomic)\n\n            char* data;    // Contents (on heap) are aligned to T's alignment\n\n            const size_t size;\n\n            AE_FORCEINLINE size_t sizeMask() const {\n                return size - 1;\n            }\n\n\n            // size must be a power of two (and greater than 0)\n            Block(size_t const& _size)\n                : front(0), tail(0), next(nullptr), size(_size) {\n                // Allocate enough memory for an array of Ts, aligned\n                size_t alignment = std::alignment_of<T>::value;\n                data = rawData = static_cast<char*>(std::malloc(sizeof(T)* size + alignment - 1));\n                assert(rawData);\n                auto alignmentOffset = (uintptr_t)rawData % alignment;\n                if (alignmentOffset != 0) {\n                    data += alignment - alignmentOffset;\n                }\n            }\n\n            ~Block() {\n                std::free(rawData);\n            }\n\n        private:\n            // C4512 - Assignment operator could not be generated\n            Block& operator=(Block const&);\n\n        private:\n            char* rawData;\n        };\n\n    private:\n        AE_ALIGN(CACHE_LINE_SIZE)\n            weak_atomic<Block*> frontBlock;    // (Atomic) Elements are enqueued to this block\n\n        AE_ALIGN(CACHE_LINE_SIZE)\n            weak_atomic<Block*> tailBlock;    // (Atomic) Elements are dequeued from this block\n\n        AE_ALIGN(CACHE_LINE_SIZE)    // Ensure tailBlock gets its own cache line\n            size_t largestBlockSize;\n\n#ifndef NDEBUG\n        bool enqueuing;\n        bool dequeuing;\n#endif\n    };\n}\n\n#ifdef AE_VCPP\n#pragma warning(pop)\n#endif"
  },
  {
    "path": "SoA/soaUtils.h",
    "content": "///\n/// soaUtils.h\n/// Seed of Andromeda\n///\n/// Created by Benjamin Arnold on 17 Feb 2015\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// Soa specific generic utilities\n///\n\n#pragma once\n\n#ifndef soaUtils_h__\n#define soaUtils_h__\n\n#include \"Constants.h\"\n\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/types.h>\n#include <chrono>\n#include <cstdio>\n#include <ctime> \n#include <iomanip>\n#include <sstream>\n#include <string> \n\n/************************************************************************/\n/* Debugging Utilities                                                  */\n/************************************************************************/\n#define PRINT_VEC_TYPE(TYPE, SYM) \\\ninline void printVec(const char* desc, const TYPE##v2& vec) { \\\n    printf(\"%s <%\"#SYM\", %\"#SYM\">\\n\", desc, vec.x, vec.y); \\\n} \\\ninline void printVec(const char* desc, const TYPE##v3& vec) { \\\n    printf(\"%s <%\"#SYM\", %\"#SYM\", %\"#SYM\">\\n\", desc, vec.x, vec.y, vec.z); \\\n} \\\ninline void printVec(const char* desc, const TYPE##v4& vec) { \\\n    printf(\"%s <%\"#SYM\", %\"#SYM\", %\"#SYM\", %\"#SYM\">\\n\", desc, vec.x, vec.y, vec.z, vec.w); \\\n}\nPRINT_VEC_TYPE(f32, f)\nPRINT_VEC_TYPE(f64, lf)\nPRINT_VEC_TYPE(i16, hd)\nPRINT_VEC_TYPE(i32, d)\nPRINT_VEC_TYPE(i64, ld)\nPRINT_VEC_TYPE(ui16, hu)\nPRINT_VEC_TYPE(ui32, u)\nPRINT_VEC_TYPE(ui64, lu)\n#undef PRINT_VEC_TYPE\n\n/************************************************************************/\n/* Miscellaneous Utilities                                              */\n/************************************************************************/\n/// Gets the closest point on the AABB to the position\n/// @param pos: Position to query nearest point in relation to\n/// @param aabbPos: Position of the -x,-y,-z corner of the aabb\n/// @param aabbDims: Dimensions of the aabb\n/// @return the position of the closest point on the aabb\ninline f32v3 getClosestPointOnAABB(const f32v3& pos, const f32v3& aabbPos,\n                                   const f32v3& aabbDims) {\n    return f32v3((pos.x <= aabbPos.x) ? aabbPos.x : ((pos.x > aabbPos.x + aabbDims.x) ?\n           (aabbPos.x + aabbDims.x) : pos.x),\n           (pos.y <= aabbPos.y) ? aabbPos.y : ((pos.y > aabbPos.y + aabbDims.y) ?\n           (aabbPos.y + aabbDims.y) : pos.y),\n           (pos.z <= aabbPos.z) ? aabbPos.z : ((pos.z > aabbPos.z + aabbDims.z) ?\n           (aabbPos.z + aabbDims.z) : pos.z));\n}\ninline f64v3 getClosestPointOnAABB(const f64v3& pos, const f64v3& aabbPos,\n                                   const f64v3& aabbDims) {\n    return f64v3((pos.x <= aabbPos.x) ? aabbPos.x : ((pos.x > aabbPos.x + aabbDims.x) ?\n           (aabbPos.x + aabbDims.x) : pos.x),\n           (pos.y <= aabbPos.y) ? aabbPos.y : ((pos.y > aabbPos.y + aabbDims.y) ?\n           (aabbPos.y + aabbDims.y) : pos.y),\n           (pos.z <= aabbPos.z) ? aabbPos.z : ((pos.z > aabbPos.z + aabbDims.z) ?\n           (aabbPos.z + aabbDims.z) : pos.z));\n}\n\n/// Moves val towards target in increments of step\ntemplate <typename T>\ninline void stepTowards(T& val, const T& target, const T& step) {\n    if (val < target) {\n        val += step;\n        if (val > target) val = target;\n    } else if (val > target) {\n        val -= step;\n        if (val < target) val = target;\n    }\n}\n\n/// Gets dot product with self, cheaper than vmath::dot because less copy\ninline f32 selfDot(const f32v3& v) {\n    return v.x * v.x + v.y * v.y + v.z * v.z;\n}\ninline f32 selfDot(const f32v4& v) {\n    return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;\n}\ninline f64 selfDot(const f64v3& v) {\n    return v.x * v.x + v.y * v.y + v.z * v.z;\n}\ninline f64 selfDot(const f64v4& v) {\n    return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;\n}\ninline i32 selfDot(const i32v3& v) {\n    return v.x * v.x + v.y * v.y + v.z * v.z;\n}\ninline i32 selfDot(const i32v4& v) {\n    return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;\n}\ninline ui32 selfDot(const ui32v3& v) {\n    return v.x * v.x + v.y * v.y + v.z * v.z;\n}\ninline ui32 selfDot(const ui32v4& v) {\n    return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;\n}\n\ninline bool dumpFramebufferImage(const nString& rootDir, const ui32v4& viewport) {\n    std::vector<ui8v4> pixels;\n    int width = (viewport.z - viewport.x);\n    int height = (viewport.w - viewport.y);\n    pixels.resize(width * height);\n    // Read pixels from framebuffer\n    glReadPixels(viewport.x, viewport.y, viewport.z, viewport.w, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());\n\n    // Use time to get file path\n    auto now = std::chrono::system_clock::now();\n    auto in_time_t = std::chrono::system_clock::to_time_t(now);\n    std::stringstream ss;\n    ss << std::put_time(std::localtime(&in_time_t), \"%Y-%m-%d-%X\");\n    nString path = rootDir + \"img-\" + ss.str() + \".png\";\n    std::replace(path.begin(), path.end(), ':', '-');\n    // Save screenshot\n    if (!vg::ImageIO().save(path, pixels.data(), width, height, vg::ImageIOFormat::RGBA_UI8)) return false;\n\n    printf(\"Made screenshot %s\\n\", path.c_str());\n    return true;\n}\n\n// No idea how this works. Something to do with prime numbers, but returns # between -1 and 1\n// It has poor distribution\ninline f64 pseudoRand(int x, int z) {\n    int n = (x & 0xFFFF) + ((z & 0x7FFF) << 16);\n    n = (n << 13) ^ n;\n    int nn = (n*(n*n * 60493 + z * 19990303) + x * 1376312589) & 0x7fffffff;\n    return ((f64)nn / 1073741824.0);\n}\n\n// Thread safe version of intel's fast random number generator\ninline ui32 fastRand(ui32 seed) {\n    return ((214013u * seed + 2531011u) >> 16) & RAND_MAX;\n}\n\n#define FULL_64 0xFFFFFFFFFFFFFFFFu\n\n// Great distribution and only a bit slower than rand()\nclass FastRandGenerator {\npublic:\n    FastRandGenerator() { m_seed[0] = 214013u; m_seed[1] = 2531011u; };\n    template<typename T>\n    FastRandGenerator(T seedX) { seed(seedX); }\n    template<typename T>\n    FastRandGenerator(T seedX, T seedY) { seed(seedX, seedY); }\n    template<typename T>\n    FastRandGenerator(T seedX, T seedY, T seedZ) { seed(seedX, seedY, seedZ); }\n\n    // Seeds the generator\n    // TODO(Ben): Not sure how good this seeding is...\n    template<typename T>\n    inline void seed(T seed) {\n        std::hash<T> h;\n        m_seed[0] = ((ui64)h(seed) << 32) | (ui64)seed;\n        m_seed[1] = m_seed[0] | (m_seed[0] << 32);\n        gen();\n    }\n    template<typename T>\n    inline void seed(T seedX, T seedY) {\n        std::hash<T> h;\n        ui64 hx = h(seedX);\n        ui64 hy = h(seedY);\n        m_seed[0] = (ui64)fastRand(hx) | (((ui64)hy + 214013u) << 32);\n        m_seed[1] = (ui64)fastRand(hy) | (m_seed[0] << 32);\n        gen();\n    }\n    template<typename T>\n    inline void seed(T seedX, T seedY, T seedZ) {\n        std::hash<T> h;\n        ui64 hx = h(seedX);\n        ui64 hy = h(seedY);\n        m_seed[0] = (ui64)hx | ((ui64)hy << 32);\n        m_seed[1] = ((ui64)hy | ((ui64)hx << 32)) ^ (ui64)seedZ;\n        gen();\n    }\n\n    // Generates a random 64 bit number\n    inline ui64 gen() {\n        ui64 x = m_seed[0];\n        const ui64 y = m_seed[1];\n        m_seed[0] = y;\n        x ^= x << 23; // a\n        x ^= x >> 17; // b\n        x ^= y ^ (y >> 26); // c\n        m_seed[1] = x;\n        return x + y;\n    }\n   \n    // Generates number between 0 and 1\n    inline f64 genlf() {\n        ui64 x = m_seed[0];\n        const ui64 y = m_seed[1];\n        m_seed[0] = y;\n        x ^= x << 23; // a\n        x ^= x >> 17; // b\n        x ^= y ^ (y >> 26); // c\n        m_seed[1] = x;\n        return (f64)(x + y) / (f64)FULL_64;\n    }\n\nprivate:\n    ui64 m_seed[2];\n};\n\n\n// Math stuff //TODO(Ben): Move this to vorb?\n// atan2 approximation for doubles for GLSL\n// using http://lolengine.net/wiki/doc/maths/remez\ninline f64 fastAtan2(f64 y, f64 x) {\n    const f64 atan_tbl[] = {\n        -3.333333333333333333333333333303396520128e-1,\n        1.999999117496509842004185053319506031014e-1,\n        -1.428514132711481940637283859690014415584e-1,\n        1.110012236849539584126568416131750076191e-1,\n        -8.993611617787817334566922323958104463948e-2,\n        7.212338962134411520637759523226823838487e-2,\n        -5.205055255952184339031830383744136009889e-2,\n        2.938542391751121307313459297120064977888e-2,\n        -1.079891788348568421355096111489189625479e-2,\n        1.858552116405489677124095112269935093498e-3\n    };\n\n    /* argument reduction:\n    arctan (-x) = -arctan(x);\n    arctan (1/x) = 1/2 * pi - arctan (x), when x > 0\n    */\n\n    f64 ax = abs(x);\n    f64 ay = abs(y);\n    f64 t0 = ax > ay ? ax : ay; // max\n    f64 t1 = ax < ay ? ax : ay; // min\n\n    f64 a = 1 / t0;\n    a *= t1;\n\n    f64 s = a * a;\n    f64 p = atan_tbl[9];\n\n    p = fma(fma(fma(fma(fma(fma(fma(fma(fma(fma(p, s,\n        atan_tbl[8]), s,\n        atan_tbl[7]), s,\n        atan_tbl[6]), s,\n        atan_tbl[5]), s,\n        atan_tbl[4]), s,\n        atan_tbl[3]), s,\n        atan_tbl[2]), s,\n        atan_tbl[1]), s,\n        atan_tbl[0]), s*a, a);\n\n    f64 r = ay > ax ? (1.57079632679489661923 - p) : p;\n\n    r = x < 0 ? 3.14159265358979323846 - r : r;\n    r = y < 0 ? -r : r;\n\n    return r;\n}\n\n/// For logarithmic z-buffer shaders\ninline f32 computeZCoef(f32 zFar) {\n    return 2.0f / log2(zFar + 1.0f);\n}\n\n/// Get distance from a chunk\ninline f32 computeDistance2FromChunk(const f64v3& chunkPos, const f64v3& p) {\n    f64 dx = ((p.x <= chunkPos.x) ? chunkPos.x : ((p.x > chunkPos.x + CHUNK_WIDTH) ? (chunkPos.x + CHUNK_WIDTH) : p.x));\n    f64 dy = ((p.y <= chunkPos.y) ? chunkPos.y : ((p.y > chunkPos.y + CHUNK_WIDTH) ? (chunkPos.y + CHUNK_WIDTH) : p.y));\n    f64 dz = ((p.z <= chunkPos.z) ? chunkPos.z : ((p.z > chunkPos.z + CHUNK_WIDTH) ? (chunkPos.z + CHUNK_WIDTH) : p.z));\n    dx = dx - p.x;\n    dy = dy - p.y;\n    dz = dz - p.z;\n    // We don't sqrt the distance since sqrt is slow\n    return (f32)(dx*dx + dy*dy + dz*dz);\n}\n\n#endif // soaUtils_h__\n"
  },
  {
    "path": "SoA/stdafx.cpp",
    "content": "#include \"stdafx.h\""
  },
  {
    "path": "SoA/stdafx.h",
    "content": "///\n/// stdafx.h\n/// Seed of Andromeda\n///\n/// Created by Cristian Zaloj on 29 Dec 2014\n/// Copyright 2014 Regrowth Studios\n/// MIT License\n///\n/// Summary:\n/// PCH for Seed of Andromeda\n///\n\n#pragma once\n\n#ifndef stdafx_h__SoA\n#define stdafx_h__SoA\n\n//#include <Vorb/stdafx.h>\n/************************************************************************/\n/* C Libraries                                                          */\n/************************************************************************/\n#include <cmath>\n#include <cstdio>\n#include <cstdlib>\n/************************************************************************/\n/* Stream libraries                                                     */\n/************************************************************************/\n#include <fstream>\n#include <iostream>\n#include <sstream>\n/************************************************************************/\n/* STL Containers                                                       */\n/************************************************************************/\n#include <map>\n#include <queue>\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n/************************************************************************/\n/* Other                                                                */\n/************************************************************************/\n#include <mutex>\n#include <string>\n#include <thread>\n\n// TODO: Distribute OpenGL from this location\n#include <GL/glew.h>\n\n\n#endif // stdafx_h__SoA"
  },
  {
    "path": "SoA/svd.cpp",
    "content": "/*\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\n* distribute this software, either in source code form or as a compiled\n* binary, for any purpose, commercial or non-commercial, and by any\n* means.\n*\n* In jurisdictions that recognize copyright laws, the author or authors\n* of this software dedicate any and all copyright interest in the\n* software to the public domain. We make this dedication for the benefit\n* of the public at large and to the detriment of our heirs and\n* successors. We intend this dedication to be an overt act of\n* relinquishment in perpetuity of all present and future rights to this\n* software under copyright law.\n*\n* THE SOFTWARE IS 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR\n* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n* OTHER DEALINGS IN THE SOFTWARE.\n*\n* For more information, please refer to <http://unlicense.org/>\n*/\n#include \"stdafx.h\"\n#include \"svd.h\"\n#include <math.h>\n\nnamespace svd {\n\n    Mat3::Mat3() {\n        this->clear();\n    }\n\n    Mat3::Mat3(const float m00, const float m01, const float m02,\n               const float m10, const float m11, const float m12,\n               const float m20, const float m21, const float m22) {\n        this->set(m00, m01, m02, m10, m11, m12, m20, m21, m22);\n    }\n\n    Mat3::Mat3(const Mat3 &rhs) {\n        this->set(rhs);\n    }\n\n    void Mat3::clear() {\n        this->set(0, 0, 0, 0, 0, 0, 0, 0, 0);\n    }\n\n    void Mat3::set(const float m00, const float m01, const float m02,\n                   const float m10, const float m11, const float m12,\n                   const float m20, const float m21, const float m22) {\n        this->m00 = m00;\n        this->m01 = m01;\n        this->m02 = m02;\n        this->m10 = m10;\n        this->m11 = m11;\n        this->m12 = m12;\n        this->m20 = m20;\n        this->m21 = m21;\n        this->m22 = m22;\n    }\n\n    void Mat3::set(const Mat3 &rhs) {\n        this->set(rhs.m00, rhs.m01, rhs.m02, rhs.m10, rhs.m11, rhs.m12, rhs.m20,\n                  rhs.m21, rhs.m22);\n    }\n\n    void Mat3::setSymmetric(const SMat3 &rhs) {\n        this->setSymmetric(rhs.m00, rhs.m01, rhs.m02, rhs.m11, rhs.m12, rhs.m22);\n    }\n\n    void Mat3::setSymmetric(const float a00, const float a01, const float a02,\n                            const float a11, const float a12, const float a22) {\n        this->set(a00, a01, a02, a01, a11, a12, a02, a12, a22);\n    }\n\n    SMat3::SMat3() {\n        this->clear();\n    }\n\n    SMat3::SMat3(const float m00, const float m01, const float m02,\n                 const float m11, const float m12, const float m22) {\n        this->setSymmetric(m00, m01, m02, m11, m12, m22);\n    }\n\n    SMat3::SMat3(const SMat3 &rhs) {\n        this->setSymmetric(rhs);\n    }\n\n    void SMat3::clear() {\n        this->setSymmetric(0, 0, 0, 0, 0, 0);\n    }\n\n    void SMat3::setSymmetric(const SMat3 &rhs) {\n        this->setSymmetric(rhs.m00, rhs.m01, rhs.m02, rhs.m11, rhs.m12, rhs.m22);\n    }\n\n    void SMat3::setSymmetric(const float a00, const float a01, const float a02,\n                             const float a11, const float a12, const float a22) {\n        this->m00 = a00;\n        this->m01 = a01;\n        this->m02 = a02;\n        this->m11 = a11;\n        this->m12 = a12;\n        this->m22 = a22;\n    }\n\n    Vec3::Vec3() : x(0), y(0), z(0) {}\n\n    Vec3::Vec3(const Vec3 &rhs)// : Vec3()\n    {\n        this->set(rhs);\n    }\n\n    Vec3::Vec3(const float x, const float y, const float z)// : Vec3()\n    {\n        this->set(x, y, z);\n    }\n\n    void Vec3::clear() {\n        this->set(0, 0, 0);\n    }\n\n    void Vec3::set(const float x, const float y, const float z) {\n        this->x = x;\n        this->y = y;\n        this->z = z;\n    }\n\n    void Vec3::set(const Vec3 &rhs) {\n        this->set(rhs.x, rhs.y, rhs.z);\n    }\n\n#ifndef NO_OSTREAM\n    std::ostream &operator<<(std::ostream &os, const Mat3 &m) {\n        os << \"[[\" << m.m00 << \", \" << m.m01 << \", \" << m.m02 << \"]\" <<\n            std::endl;\n        os << \" [\" << m.m10 << \", \" << m.m11 << \", \" << m.m12 << \"]\" <<\n            std::endl;\n        os << \" [\" << m.m20 << \", \" << m.m21 << \", \" << m.m22 << \"]]\";\n        return os;\n    }\n\n    std::ostream &operator<<(std::ostream &os, const SMat3 &m) {\n        os << \"[[\" << m.m00 << \", \" << m.m01 << \", \" << m.m02 << \"]\" <<\n            std::endl;\n        os << \" [\" << m.m01 << \", \" << m.m11 << \", \" << m.m12 << \"]\" <<\n            std::endl;\n        os << \" [\" << m.m02 << \", \" << m.m12 << \", \" << m.m22 << \"]]\";\n        return os;\n    }\n\n    std::ostream &operator<<(std::ostream &os, const Vec3 &v) {\n        os << \"[\" << v.x << \", \" << v.y << \", \" << v.z << \"]\";\n        return os;\n    }\n#endif\n\n    float MatUtils::fnorm(const Mat3 &a) {\n        return sqrt((a.m00 * a.m00) + (a.m01 * a.m01) + (a.m02 * a.m02)\n                    + (a.m10 * a.m10) + (a.m11 * a.m11) + (a.m12 * a.m12)\n                    + (a.m20 * a.m20) + (a.m21 * a.m21) + (a.m22 * a.m22));\n    }\n\n    float MatUtils::fnorm(const SMat3 &a) {\n        return sqrt((a.m00 * a.m00) + (a.m01 * a.m01) + (a.m02 * a.m02)\n                    + (a.m01 * a.m01) + (a.m11 * a.m11) + (a.m12 * a.m12)\n                    + (a.m02 * a.m02) + (a.m12 * a.m12) + (a.m22 * a.m22));\n    }\n\n    float MatUtils::off(const Mat3 &a) {\n        return sqrt((a.m01 * a.m01) + (a.m02 * a.m02) + (a.m10 * a.m10)\n                    + (a.m12 * a.m12) + (a.m20 * a.m20) + (a.m21 * a.m21));\n    }\n\n    float MatUtils::off(const SMat3 &a) {\n        return sqrt(2 * ((a.m01 * a.m01) + (a.m02 * a.m02) + (a.m12 * a.m12)));\n    }\n\n    void MatUtils::mmul(Mat3 &out, const Mat3 &a, const Mat3 &b) {\n        out.set(a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20,\n                a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21,\n                a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22,\n                a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20,\n                a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21,\n                a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22,\n                a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20,\n                a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21,\n                a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22);\n    }\n\n    void MatUtils::mmul_ata(SMat3 &out, const Mat3 &a) {\n        out.setSymmetric(a.m00 * a.m00 + a.m10 * a.m10 + a.m20 * a.m20,\n                         a.m00 * a.m01 + a.m10 * a.m11 + a.m20 * a.m21,\n                         a.m00 * a.m02 + a.m10 * a.m12 + a.m20 * a.m22,\n                         a.m01 * a.m01 + a.m11 * a.m11 + a.m21 * a.m21,\n                         a.m01 * a.m02 + a.m11 * a.m12 + a.m21 * a.m22,\n                         a.m02 * a.m02 + a.m12 * a.m12 + a.m22 * a.m22);\n    }\n\n    void MatUtils::transpose(Mat3 &out, const Mat3 &a) {\n        out.set(a.m00, a.m10, a.m20, a.m01, a.m11, a.m21, a.m02, a.m12, a.m22);\n    }\n\n    void MatUtils::vmul(Vec3 &out, const Mat3 &a, const Vec3 &v) {\n        out.x = (a.m00 * v.x) + (a.m01 * v.y) + (a.m02 * v.z);\n        out.y = (a.m10 * v.x) + (a.m11 * v.y) + (a.m12 * v.z);\n        out.z = (a.m20 * v.x) + (a.m21 * v.y) + (a.m22 * v.z);\n    }\n\n    void MatUtils::vmul_symmetric(Vec3 &out, const SMat3 &a, const Vec3 &v) {\n        out.x = (a.m00 * v.x) + (a.m01 * v.y) + (a.m02 * v.z);\n        out.y = (a.m01 * v.x) + (a.m11 * v.y) + (a.m12 * v.z);\n        out.z = (a.m02 * v.x) + (a.m12 * v.y) + (a.m22 * v.z);\n    }\n\n    void VecUtils::addScaled(Vec3 &v, const float s, const Vec3 &rhs) {\n        v.x += s * rhs.x;\n        v.y += s * rhs.y;\n        v.z += s * rhs.z;\n    }\n\n    float VecUtils::dot(const Vec3 &a, const Vec3 &b) {\n        return a.x * b.x + a.y * b.y + a.z * b.z;\n    }\n\n    void VecUtils::normalize(Vec3 &v) {\n        const float len2 = VecUtils::dot(v, v);\n\n        if (fabs(len2) < 1e-12) {\n            v.clear();\n        } else {\n            VecUtils::scale(v, 1 / sqrt(len2));\n        }\n    }\n\n    void VecUtils::scale(Vec3 &v, const float s) {\n        v.x *= s;\n        v.y *= s;\n        v.z *= s;\n    }\n\n    void VecUtils::sub(Vec3 &c, const Vec3 &a, const Vec3 &b) {\n        const float v0 = a.x - b.x;\n        const float v1 = a.y - b.y;\n        const float v2 = a.z - b.z;\n        c.x = v0;\n        c.y = v1;\n        c.z = v2;\n    }\n\n    void Givens::rot01_post(Mat3 &m, const float c, const float s) {\n        const float m00 = m.m00, m01 = m.m01, m10 = m.m10, m11 = m.m11, m20 = m.m20,\n            m21 = m.m21;\n        m.set(c * m00 - s * m01, s * m00 + c * m01, m.m02, c * m10 - s * m11,\n              s * m10 + c * m11, m.m12, c * m20 - s * m21, s * m20 + c * m21, m.m22);\n    }\n\n    void Givens::rot02_post(Mat3 &m, const float c, const float s) {\n        const float m00 = m.m00, m02 = m.m02, m10 = m.m10, m12 = m.m12,\n            m20 = m.m20, m22 = m.m22;\n        m.set(c * m00 - s * m02, m.m01, s * m00 + c * m02, c * m10 - s * m12, m.m11,\n              s * m10 + c * m12, c * m20 - s * m22, m.m21, s * m20 + c * m22);\n    }\n\n    void Givens::rot12_post(Mat3 &m, const float c, const float s) {\n        const float m01 = m.m01, m02 = m.m02, m11 = m.m11, m12 = m.m12,\n            m21 = m.m21, m22 = m.m22;\n        m.set(m.m00, c * m01 - s * m02, s * m01 + c * m02, m.m10, c * m11 - s * m12,\n              s * m11 + c * m12, m.m20, c * m21 - s * m22, s * m21 + c * m22);\n    }\n\n    static void calcSymmetricGivensCoefficients(const float a_pp,\n                                                const float a_pq, const float a_qq, float &c, float &s) {\n        if (a_pq == 0) {\n            c = 1;\n            s = 0;\n            return;\n        }\n\n        const float tau = (a_qq - a_pp) / (2 * a_pq);\n        const float stt = sqrt(1.0f + tau * tau);\n        const float tan = 1.0f / ((tau >= 0) ? (tau + stt) : (tau - stt));\n        c = 1.0f / sqrt(1.f + tan * tan);\n        s = tan * c;\n    }\n\n    void Schur2::rot01(SMat3 &m, float &c, float &s) {\n        svd::calcSymmetricGivensCoefficients(m.m00, m.m01, m.m11, c, s);\n        const float cc = c * c;\n        const float ss = s * s;\n        const float mix = 2 * c * s * m.m01;\n        m.setSymmetric(cc * m.m00 - mix + ss * m.m11, 0, c * m.m02 - s * m.m12,\n                       ss * m.m00 + mix + cc * m.m11, s * m.m02 + c * m.m12, m.m22);\n    }\n\n    void Schur2::rot02(SMat3 &m, float &c, float &s) {\n        svd::calcSymmetricGivensCoefficients(m.m00, m.m02, m.m22, c, s);\n        const float cc = c * c;\n        const float ss = s * s;\n        const float mix = 2 * c * s * m.m02;\n        m.setSymmetric(cc * m.m00 - mix + ss * m.m22, c * m.m01 - s * m.m12, 0,\n                       m.m11, s * m.m01 + c * m.m12, ss * m.m00 + mix + cc * m.m22);\n    }\n\n    void Schur2::rot12(SMat3 &m, float &c, float &s) {\n        svd::calcSymmetricGivensCoefficients(m.m11, m.m12, m.m22, c, s);\n        const float cc = c * c;\n        const float ss = s * s;\n        const float mix = 2 * c * s * m.m12;\n        m.setSymmetric(m.m00, c * m.m01 - s * m.m02, s * m.m01 + c * m.m02,\n                       cc * m.m11 - mix + ss * m.m22, 0, ss * m.m11 + mix + cc * m.m22);\n    }\n\n    static void rotate01(SMat3 &vtav, Mat3 &v) {\n        if (vtav.m01 == 0) {\n            return;\n        }\n\n        float c, s;\n        Schur2::rot01(vtav, c, s);\n        Givens::rot01_post(v, c, s);\n    }\n\n    static void rotate02(SMat3 &vtav, Mat3 &v) {\n        if (vtav.m02 == 0) {\n            return;\n        }\n\n        float c, s;\n        Schur2::rot02(vtav, c, s);\n        Givens::rot02_post(v, c, s);\n    }\n\n    static void rotate12(SMat3 &vtav, Mat3 &v) {\n        if (vtav.m12 == 0) {\n            return;\n        }\n\n        float c, s;\n        Schur2::rot12(vtav, c, s);\n        Givens::rot12_post(v, c, s);\n    }\n\n    void Svd::getSymmetricSvd(const SMat3 &a, SMat3 &vtav, Mat3 &v,\n                              const float tol,\n                              const int max_sweeps) {\n        vtav.setSymmetric(a);\n        v.set(1, 0, 0, 0, 1, 0, 0, 0, 1);\n        const float delta = tol * MatUtils::fnorm(vtav);\n\n        for (int i = 0; i < max_sweeps\n             && MatUtils::off(vtav) > delta; ++i) {\n            rotate01(vtav, v);\n            rotate02(vtav, v);\n            rotate12(vtav, v);\n        }\n    }\n\n    //static float calcError(const Mat3 &A, const Vec3 &x,\n    //                       const Vec3 &b) {\n    //    Vec3 vtmp;\n    //    MatUtils::vmul(vtmp, A, x);\n    //    VecUtils::sub(vtmp, b, vtmp);\n    //    return VecUtils::dot(vtmp, vtmp);\n    //}\n\n    static float calcError(const SMat3 &origA, const Vec3 &x,\n                           const Vec3 &b) {\n        Mat3 A;\n        Vec3 vtmp;\n        A.setSymmetric(origA);\n        MatUtils::vmul(vtmp, A, x);\n        VecUtils::sub(vtmp, b, vtmp);\n        return VecUtils::dot(vtmp, vtmp);\n    }\n\n    static float pinv(const float x, const float tol) {\n        return (fabs(x) < tol || fabs(1 / x) < tol) ? 0 : (1 / x);\n    }\n\n    void Svd::pseudoinverse(Mat3 &out, const SMat3 &d, const Mat3 &v,\n                            const float tol) {\n        const float d0 = pinv(d.m00, tol), d1 = pinv(d.m11, tol), d2 = pinv(d.m22,\n                                                                            tol);\n        out.set(v.m00 * d0 * v.m00 + v.m01 * d1 * v.m01 + v.m02 * d2 * v.m02,\n                v.m00 * d0 * v.m10 + v.m01 * d1 * v.m11 + v.m02 * d2 * v.m12,\n                v.m00 * d0 * v.m20 + v.m01 * d1 * v.m21 + v.m02 * d2 * v.m22,\n                v.m10 * d0 * v.m00 + v.m11 * d1 * v.m01 + v.m12 * d2 * v.m02,\n                v.m10 * d0 * v.m10 + v.m11 * d1 * v.m11 + v.m12 * d2 * v.m12,\n                v.m10 * d0 * v.m20 + v.m11 * d1 * v.m21 + v.m12 * d2 * v.m22,\n                v.m20 * d0 * v.m00 + v.m21 * d1 * v.m01 + v.m22 * d2 * v.m02,\n                v.m20 * d0 * v.m10 + v.m21 * d1 * v.m11 + v.m22 * d2 * v.m12,\n                v.m20 * d0 * v.m20 + v.m21 * d1 * v.m21 + v.m22 * d2 * v.m22);\n    }\n\n    float Svd::solveSymmetric(const SMat3 &A, const Vec3 &b, Vec3 &x,\n                              const float svd_tol, const int svd_sweeps, const float pinv_tol) {\n        Mat3 mtmp, pinv, V;\n        SMat3 VTAV;\n        Svd::getSymmetricSvd(A, VTAV, V, svd_tol, svd_sweeps);\n        Svd::pseudoinverse(pinv, VTAV, V, pinv_tol);\n        MatUtils::vmul(x, pinv, b);\n        return svd::calcError(A, x, b);\n    }\n\n    float\n        LeastSquares::solveLeastSquares(const Mat3 &a, const Vec3 &b, Vec3 &x,\n        const float svd_tol, const int svd_sweeps, const float pinv_tol) {\n        Mat3 at;\n        SMat3 ata;\n        Vec3 atb;\n        MatUtils::transpose(at, a);\n        MatUtils::mmul_ata(ata, a);\n        MatUtils::vmul(atb, at, b);\n        return Svd::solveSymmetric(ata, atb, x, svd_tol, svd_sweeps, pinv_tol);\n    }\n\n}"
  },
  {
    "path": "SoA/svd.h",
    "content": "/*\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\n* distribute this software, either in source code form or as a compiled\n* binary, for any purpose, commercial or non-commercial, and by any\n* means.\n*\n* In jurisdictions that recognize copyright laws, the author or authors\n* of this software dedicate any and all copyright interest in the\n* software to the public domain. We make this dedication for the benefit\n* of the public at large and to the detriment of our heirs and\n* successors. We intend this dedication to be an overt act of\n* relinquishment in perpetuity of all present and future rights to this\n* software under copyright law.\n*\n* THE SOFTWARE IS 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR\n* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n* OTHER DEALINGS IN THE SOFTWARE.\n*\n* For more information, please refer to <http://unlicense.org/>\n*/\n#ifndef SVD_H\n#define SVD_H\n#ifndef NO_OSTREAM\n#include <iostream>\n#endif\n\nnamespace svd {\n    class SMat3 {\n    public:\n        float m00, m01, m02, m11, m12, m22;\n    public:\n        SMat3();\n        SMat3(const float m00, const float m01, const float m02,\n              const float m11, const float m12, const float m22);\n        void clear();\n        void setSymmetric(const float m00, const float m01, const float m02,\n                          const float m11,\n                          const float m12, const float m22);\n        void setSymmetric(const SMat3 &rhs);\n    private:\n        SMat3(const SMat3 &rhs);\n        SMat3 &operator=(const SMat3 &rhs);\n    };\n    class Mat3 {\n    public:\n        float m00, m01, m02, m10, m11, m12, m20, m21, m22;\n    public:\n        Mat3();\n        Mat3(const float m00, const float m01, const float m02,\n             const float m10, const float m11, const float m12,\n             const float m20, const float m21, const float m22);\n        void clear();\n        void set(const float m00, const float m01, const float m02,\n                 const float m10, const float m11, const float m12,\n                 const float m20, const float m21, const float m22);\n        void set(const Mat3 &rhs);\n        void setSymmetric(const float a00, const float a01, const float a02,\n                          const float a11, const float a12, const float a22);\n        void setSymmetric(const SMat3 &rhs);\n    private:\n        Mat3(const Mat3 &rhs);\n        Mat3 &operator=(const Mat3 &rhs);\n    };\n    class Vec3 {\n    public:\n        float x, y, z;\n    public:\n        Vec3();\n        Vec3(const float x, const float y, const float z);\n        void clear();\n        void set(const float x, const float y, const float z);\n        void set(const Vec3 &rhs);\n    private:\n        Vec3(const Vec3 &rhs);\n        Vec3 &operator=(const Vec3 &rhs);\n    };\n#ifndef NO_OSTREAM\n    std::ostream &operator<<(std::ostream &os, const Mat3 &m);\n    std::ostream &operator<<(std::ostream &os, const SMat3 &m);\n    std::ostream &operator<<(std::ostream &os, const Vec3 &v);\n#endif\n    class MatUtils {\n    public:\n        static float fnorm(const Mat3 &a);\n        static float fnorm(const SMat3 &a);\n        static float off(const Mat3 &a);\n        static float off(const SMat3 &a);\n\n    public:\n        static void mmul(Mat3 &out, const Mat3 &a, const Mat3 &b);\n        static void mmul_ata(SMat3 &out, const Mat3 &a);\n        static void transpose(Mat3 &out, const Mat3 &a);\n        static void vmul(Vec3 &out, const Mat3 &a, const Vec3 &v);\n        static void vmul_symmetric(Vec3 &out, const SMat3 &a, const Vec3 &v);\n    };\n    class VecUtils {\n    public:\n        static void addScaled(Vec3 &v, const float s, const Vec3 &rhs);\n        static float dot(const Vec3 &a, const Vec3 &b);\n        static void normalize(Vec3 &v);\n        static void scale(Vec3 &v, const float s);\n        static void sub(Vec3 &c, const Vec3 &a, const Vec3 &b);\n    };\n    class Givens {\n    public:\n        static void rot01_post(Mat3 &m, const float c, const float s);\n        static void rot02_post(Mat3 &m, const float c, const float s);\n        static void rot12_post(Mat3 &m, const float c, const float s);\n    };\n    class Schur2 {\n    public:\n        static void rot01(SMat3 &out, float &c, float &s);\n        static void rot02(SMat3 &out, float &c, float &s);\n        static void rot12(SMat3 &out, float &c, float &s);\n    };\n    class Svd {\n    public:\n        static void getSymmetricSvd(const SMat3 &a, SMat3 &vtav, Mat3 &v,\n                                    const float tol, const int max_sweeps);\n        static void pseudoinverse(Mat3 &out, const SMat3 &d, const Mat3 &v,\n                                  const float tol);\n        static float solveSymmetric(const SMat3 &A, const Vec3 &b, Vec3 &x,\n                                    const float svd_tol, const int svd_sweeps, const float pinv_tol);\n    };\n    class LeastSquares {\n    public:\n        static float solveLeastSquares(const Mat3 &a, const Vec3 &b, Vec3 &x,\n                                       const float svd_tol, const int svd_sweeps, const float pinv_tol);\n    };\n};\n#endif"
  },
  {
    "path": "SoA/textureUtils.h",
    "content": "//\n// textureUtils.h\n// Seed of Andromeda\n//\n// Created by Benjamin Arnold on 2 Mar 2016\n// Copyright 2014 Regrowth Studios\n// MIT License\n//\n// Summary:\n// \n//\n\n#pragma once\n\n#ifndef textureUtils_h__\n#define textureUtils_h__\n\n#include \"Constants.h\"\n\n#include <Vorb/graphics/ImageIO.h>\n#include <Vorb/graphics/Texture.h>\n#include <Vorb/io/IOManager.h>\n#include <Vorb/types.h>\n#include <chrono>\n#include <cstdio>\n#include <ctime> \n#include <iomanip>\n#include <sstream>\n#include <string> \n\ninline void initSinglePixelTexture(VGTexture& texture, color4 pixel) {\n    glGenTextures(1, &texture);\n    glBindTexture(GL_TEXTURE_2D, texture);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixel[0]);\n    glBindTexture(GL_TEXTURE_2D, 0);\n};\n\n\n#endif // textureUtils_h__\n"
  },
  {
    "path": "VorbCopy.bat",
    "content": "@ECHO OFF\nIF DEFINED VORB_PATH ( GOTO PATH_ENV )\nIF EXIST Vorb\\ ( GOTO PATH_SAME )\nIF EXIST ..\\Vorb\\ ( GOTO PATH_ROOT )\nIF EXIST deps\\Vorb\\ ( GOTO PATH_DEPS )\n\nECHO No path for Vorb found, please add to the environment variables as \"VORB_PATH\"\nPAUSE\nEXIT 1\n\n:PATH_ENV\nECHO Using VORB_PATH environment variable\nGOTO VORB_COPY\n\n:PATH_SAME\nECHO Vorb was found in the same directory\nSET VORB_PATH=Vorb\nGOTO VORB_COPY\n\n:PATH_ROOT\nECHO Vorb was found in the parent directory\nSET VORB_PATH=..\\Vorb\nGOTO VORB_COPY\n\n:PATH_DEPS\nECHO Vorb was found in the deps directory\nSET VORB_PATH=deps\\Vorb\nGOTO VORB_COPY\n\n:VORB_COPY\nPAUSE\nROBOCOPY /E \"%VORB_PATH%\\include\" \"deps\\include\\Vorb\" *\nROBOCOPY /E \"%VORB_PATH%\\deps\\lib\\Win32\" \"deps\\lib\\Win32\" *\nROBOCOPY /E \"%VORB_PATH%\\deps\\lib\\x64\" \"deps\\lib\\x64\" *\nCOPY  /Y \"%VORB_PATH%\\bin\\Win32\\Release\\Vorb.lib \" \"deps\\lib\\Win32\\Vorb.lib\"\nCOPY  /Y \"%VORB_PATH%\\bin\\Win32\\Debug\\Vorb-d.lib \" \"deps\\lib\\Win32\\Vorb-d.lib\"\nCOPY  /Y \"%VORB_PATH%\\bin\\x64\\Release\\Vorb.lib \"   \"deps\\lib\\x64\\Vorb.lib\"\nCOPY  /Y \"%VORB_PATH%\\bin\\x64\\Debug\\Vorb-d.lib \"   \"deps\\lib\\x64\\Vorb-d.lib\"\nEXIT 0"
  },
  {
    "path": "appveyor.yml",
    "content": "# Windows (https://github.com/travis-ci-tester/toolchain-table)\n\nenvironment:\n  global:\n    # This variable used only if '--upload' added to 'jenkins.py'\n    GITHUB_USER_PASSWORD:\n           secure: wG0IMoOCj/h0cQ2sClQlkHIy3JNaqt6VYJ0E3AY8pwnCeFeFFcufmrRxdKw7PQ7E #soa\n#           secure: 8msFf0QF4JUIjZKukMnJItvIQWa+1gU2Hv/k0StI0HtzeFP1fJddEBcqIIQd4+nw #krazer\n\n  matrix:\n\n    # compile issues with VS2017\n#    - TOOLCHAIN: \"ninja-vs-15-2017-win64-cxx17\"\n#      PROJECT_DIR: .\\\n#      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n#\n#    - TOOLCHAIN: \"nmake-vs-15-2017-win64-cxx17\"\n#      PROJECT_DIR: .\\\n#      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n#\n    - TOOLCHAIN: \"vs-15-2017-win64-cxx17\"\n      PROJECT_DIR: .\\\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      HUNTER_BINARY_DIR: C:\\__BIN\n\n    - TOOLCHAIN: \"vs-14-2015-win64\"\n      PROJECT_DIR: .\\\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015\n      HUNTER_BINARY_DIR: C:\\__BIN\n\n#    - TOOLCHAIN: \"mingw-cxx17\"\n#      PROJECT_DIR: .\\\n#      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015\n#\n#    - TOOLCHAIN: \"msys-cxx17\"\n#      PROJECT_DIR: .\\\n#      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015\n\ninstall:\n  # Python 3\n  - cmd: set PATH=C:\\Python34-x64;C:\\Python34-x64\\Scripts;%PATH%\n\n  # Install Python package 'requests', 'gitpython'\n  - cmd: pip install requests\n  - cmd: pip install gitpython\n\n  # Install latest Polly toolchains and scripts\n  - cmd: appveyor DownloadFile https://github.com/ruslo/polly/archive/master.zip\n  - cmd: 7z x master.zip\n  - cmd: set POLLY_ROOT=%cd%\\polly-master\n\n  # Install dependencies (CMake, Ninja)\n  - cmd: python %POLLY_ROOT%\\bin\\install-ci-dependencies.py\n\n  # Tune locations\n  - cmd: set PATH=%cd%\\_ci\\cmake\\bin;%PATH%\n  - cmd: set PATH=%cd%\\_ci\\ninja;%PATH%\n\n  - cmd: git submodule update --init Vorb\n\n  # Remove entry with sh.exe from PATH to fix error with MinGW toolchain\n  # (For MinGW make to work correctly sh.exe must NOT be in your path)\n  # * http://stackoverflow.com/a/3870338/2288008\n  - cmd: set PATH=%PATH:C:\\Program Files\\Git\\usr\\bin;=%\n\n  # Save git.exe in HUNTER_GIT_EXECUTABLE for upload\n  # * https://docs.hunter.sh/en/latest/reference/user-variables.html#hunter-git-executable\n  # Variable will be used in CMake so it's okay to use Unix style '/'\n  - cmd: set HUNTER_GIT_EXECUTABLE=C:/Program Files/Git/bin/git.exe\n\n  - cmd: set MINGW_PATH=C:\\mingw-w64\\x86_64-7.2.0-posix-seh-rt_v5-rev1\\mingw64\\bin\n\n  # MSYS2 location\n  - cmd: set MSYS_PATH=C:\\msys64\\usr\\bin\n\n  # Visual Studio 15 2017: Mimic behavior of older versions\n  - cmd: set VS150COMNTOOLS=C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\Common7\\Tools\n\nbuild_script:\n  - cmd: python .\\jenkins.py\n\n# http://www.appveyor.com/docs/branches#white-and-blacklisting\n# Exclude branch 'pkg.template'. Nothing to build there.\nbranches:\n  except:\n    - pkg.template\n    - /^pr\\..*/\n    - /^v[0-9]+\\.[0-9]+\\.[0-9]+$/"
  },
  {
    "path": "build.bat",
    "content": "@ECHO OFF && PUSHD \"%~dp0\" && SETLOCAL\n\nSET VS_TARGET=\"2015\"\nSET BUILD_CLEAN=\"false\"\nSET \"CMAKE_PARAMS=\"\nSET \"BUILD_PARAMS=\"\n\nGOTO Argloop\n\n:Help\nECHO \"\\n\"\nECHO \"    /--------------\\\\ \\n    |  Build Help  |\\n    \\\\--------------/\\n\\n\"\nECHO \"        Build flags:\\n\"\nECHO \"            --clean             | -c       ---   Clean build, removes all previous artefacts.\\n\"\nECHO \"        CMake flags:\\n\"\nECHO \"            --release           | -r       ---   Compile in release mode.\\n\"\nECHO \"            --debug             | -d       ---   Compile in debug mode.\\n\"\nECHO \"            --cxx17             | -17      ---   Target C++17 (otherwise targets C++14).\\n\"\nECHO \"            --no-gdb            | -ng      ---   Add OS specific debug symbols rather than GDB's.\\n\"\nECHO \"            --no-extra-debug    | -ned     ---   Don't add extra debug symbols.\\n\"\nECHO \"            --no-optimise-debug | -nod     ---   Don't optimise debug mode builds.\\n\"\nECHO \"        Make flags:\\n\"\nECHO \"            --verbose           | -v       ---   Run make with verbose set on.\\n\"\nECHO \"\\n\"\nGOTO ArgloopContinue\n\n:Clean\nSET BUILD_CLEAN=\"true\"\nSET \"BUILD_PARAMS=%BUILD_PARAMS% --clean-first\"\nGOTO ArgloopContinue\n\n:Release\nSET \"CMAKE_PARAMS=%CMAKE_PARAMS% -DCMAKE_BUILD_TYPE=Release\"\nGOTO ArgloopContinue\n\n:Debug\nSET \"CMAKE_PARAMS=%CMAKE_PARAMS% -DCMAKE_BUILD_TYPE=Debug\"\nGOTO ArgloopContinue\n\n:Cxx17\nSET \"CMAKE_PARAMS=%CMAKE_PARAMS% -DTARGET_CXX_17=On\"\nGOTO ArgloopContinue\n\n:NoGDB\nSET \"CMAKE_PARAMS=%CMAKE_PARAMS% -DUSING_GDB=Off\"\nGOTO ArgloopContinue\n\n:NoExtraDebug\nSET \"CMAKE_PARAMS=%CMAKE_PARAMS% -DEXTRA_DEBUG=Off\"\nGOTO ArgloopContinue\n\n:NoOptimiseDebug\nSET \"CMAKE_PARAMS=%CMAKE_PARAMS% -DOPTIMISE_ON_DEBUG=Off\"\nGOTO ArgloopContinue\n\n:Verbose\nSET \"BUILD_PARAMS=%BUILD_PARAMS% -- VERBOSE=1\"\nGOTO ArgloopContinue\n\n:Argloop\n    IF \"%1\"==\"-h\" (\n        GOTO Help\n    ) ELSE IF \"%1\"==\"--help\" (\n        GOTO Help\n    ) ELSE IF \"%1\"==\"-c\" (\n        GOTO Clean\n    ) ELSE IF \"%1\"==\"--clean\" (\n        GOTO Clean\n    ) ELSE IF \"%1\"==\"-r\" (\n        GOTO Release\n    ) ELSE IF \"%1\"==\"--release\" (\n        GOTO Release\n    ) ELSE IF \"%1\"==\"-d\" (\n        GOTO Debug\n    ) ELSE IF \"%1\"==\"--debug\" (\n        GOTO Debug\n    ) ELSE IF \"%1\"==\"-17\" (\n        GOTO Cxx17\n    ) ELSE IF \"%1\"==\"--cxx17\" (\n        GOTO Cxx17\n    ) ELSE IF \"%1\"==\"-ng\" (\n        GOTO NoGDB\n    ) ELSE IF \"%1\"==\"--no-gdb\" (\n        GOTO NoGDB\n    ) ELSE IF \"%1\"==\"-ned\" (\n        GOTO NoExtraDebug\n    ) ELSE IF \"%1\"==\"--no-extra-debug\" (\n        GOTO NoExtraDebug\n    ) ELSE IF \"%1\"==\"-nod\" (\n        GOTO NoOptimiseDebug\n    ) ELSE IF \"%1\"==\"--no-optimise-debug\" (\n        GOTO NoOptimiseDebug\n    ) ELSE IF \"%1\"==\"-v\" (\n        GOTO Verbose\n    ) ELSE IF \"%1\"==\"--verbose\" (\n        GOTO Verbose\n    ) ELSE IF NOT \"%1\"==\"\" (\n        ECHO \"Error: Do not recognise argument %1.\"\n        EXIT /B 1\n    ) ELSE (\n        GOTO ArgloopBreak\n    )\n    :ArgloopContinue\n    SHIFT\nGOTO Argloop\n:ArgloopBreak\n\nIF EXIST \"build\" (\n    IF \"%BUILD_CLEAN%\"==\"true\" (\n        RMDIR build /S /Q\n    )\n) ELSE (\n    MKDIR build\n)\n\nCD build\n\nSET \"CMAKE_COMMAND=cmake %CMAKE_PARAMS% -G \"Visual Studio 14 2015 Win64\" ../\"\n%CMAKE_COMMAND%\n\nSET \"BUILD_COMMAND=cmake --build . %MAKE_PARAMS%\"\n%BUILD_COMMAND%\n\nCD ../\n"
  },
  {
    "path": "build.sh",
    "content": "#!/bin/bash\n\nBUILD_CLEAN=false\nBUILD_TYPE=\"-DCMAKE_BUILD_TYPE=Debug\"\nCMAKE_PARAMS=\"\"\nMAKE_PARAMS=\"\"\n\nwhile test $# -gt 0\ndo\n    case \"$1\" in\n        -h|--help)\n            printf -- \"\\n\"\n            printf -- \"    /--------------\\\\ \\n    |  Build Help  |\\n    \\\\--------------/\\n\\n\"\n            printf -- \"        Build flags:\\n\"\n            printf -- \"            --clean             | -c       ---   Clean build, removes all previous artefacts.\\n\"\n            printf -- \"        CMake flags:\\n\"\n            printf -- \"            --release           | -r       ---   Compile in release mode.\\n\"\n            printf -- \"            --debug             | -d       ---   Compile in debug mode.\\n\"\n            printf -- \"            --cxx17             | -17      ---   Target C++17 (otherwise targets C++14).\\n\"\n            printf -- \"            --clang             | -cl      ---   Compiles using clang rather than gcc.\\n\"\n            printf -- \"            --no-gdb            | -ng      ---   Add OS specific debug symbols rather than GDB's.\\n\"\n            printf -- \"            --no-extra-debug    | -ned     ---   Don't add extra debug symbols.\\n\"\n            printf -- \"            --no-optimise-debug | -nod     ---   Don't optimise debug mode builds.\\n\"\n            printf -- \"        Make flags:\\n\"\n            printf -- \"            --jobs X            | -j X     ---   Run compilation on X number of threads.\\n\"\n            printf -- \"            --verbose           | -v       ---   Run make with verbose set on.\\n\"\n            printf -- \"\\n\"\n            exit 0\n            ;;\n        -c|--clean)\n            BUILD_CLEAN=true\n            ;;\n        -r|--release)\n            BUILD_TYPE=\"-DCMAKE_BUILD_TYPE=Release\"\n            ;;\n        -d|--debug)\n            BUILD_TYPE=\"-DCMAKE_BUILD_TYPE=Debug\"\n            ;;\n        -17|--cxx17)\n            CMAKE_PARAMS=\"$CMAKE_PARAMS -DTARGET_CXX_17=On\"\n            ;;\n        -cl|--clang)\n            CMAKE_PARAMS=\"$CMAKE_PARAMS -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_C_COMPILER=/usr/bin/clang\"\n            ;;\n        -ng|--no-gdb)\n            CMAKE_PARAMS=\"$CMAKE_PARAMS -DUSING_GDB=Off\"\n            ;;\n        -ned|--no-extra-debug)\n            CMAKE_PARAMS=\"$CMAKE_PARAMS -DEXTRA_DEBUG=Off\"\n            ;;\n        -nod|--no-optimise-debug)\n            CMAKE_PARAMS=\"$CMAKE_PARAMS -DOPTIMISE_ON_DEBUG=Off\"\n            ;;\n        -j|--jobs)\n            if ! [[ $2 =~ ^[0-9]+$ ]] ; then\n                echo \"Error: Saw argument --jobs but it was not followed by a number of jobs to run.\"\n                exit 1\n            fi\n            MAKE_PARAMS=\"$MAKE_PARAMS -j$2\"\n            shift\n            ;;\n        -v|--verbose)\n            MAKE_PARAMS=\"$MAKE_PARAMS VERBOSE=1\"\n            ;;\n        *)\n            echo \"Error: Do not recognise argument $1.\"\n            exit 1\n            ;;\n    esac\n    shift\ndone\n\nif [ -d \"build\"  ] ; then\n    if [ \"$BUILD_CLEAN\" = true ] ; then\n        rm -rf build/*\n    fi\nelse\n    mkdir build\nfi\n\ncd build\n\neval \"cmake ../ $CMAKE_PARAMS $BUILD_TYPE\"\n\neval \"make $MAKE_PARAMS\"\n\ncd ../\n"
  },
  {
    "path": "cmake/hunter/HunterGate.cmake",
    "content": "# Copyright (c) 2013-2019, Ruslan Baratov\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#\n# * Redistributions of source code must retain the above copyright notice, this\n#   list of conditions and the following disclaimer.\n#\n# * Redistributions in binary form must reproduce the above copyright notice,\n#   this list of conditions and the following disclaimer in the documentation\n#   and/or other materials provided with the distribution.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n# This is a gate file to Hunter package manager.\n# Include this file using `include` command and add package you need, example:\n#\n#     cmake_minimum_required(VERSION 3.2)\n#\n#     include(\"cmake/HunterGate.cmake\")\n#     HunterGate(\n#         URL \"https://github.com/path/to/hunter/archive.tar.gz\"\n#         SHA1 \"798501e983f14b28b10cda16afa4de69eee1da1d\"\n#     )\n#\n#     project(MyProject)\n#\n#     hunter_add_package(Foo)\n#     hunter_add_package(Boo COMPONENTS Bar Baz)\n#\n# Projects:\n#     * https://github.com/hunter-packages/gate/\n#     * https://github.com/ruslo/hunter\n\noption(HUNTER_ENABLED \"Enable Hunter package manager support\" ON)\n\nif(HUNTER_ENABLED)\n  if(CMAKE_VERSION VERSION_LESS \"3.2\")\n    message(\n        FATAL_ERROR\n        \"At least CMake version 3.2 required for Hunter dependency management.\"\n        \" Update CMake or set HUNTER_ENABLED to OFF.\"\n    )\n  endif()\nendif()\n\ninclude(CMakeParseArguments) # cmake_parse_arguments\n\noption(HUNTER_STATUS_PRINT \"Print working status\" ON)\noption(HUNTER_STATUS_DEBUG \"Print a lot info\" OFF)\noption(HUNTER_TLS_VERIFY \"Enable/disable TLS certificate checking on downloads\" ON)\n\nset(HUNTER_ERROR_PAGE \"https://docs.hunter.sh/en/latest/reference/errors\")\n\nfunction(hunter_gate_status_print)\n  if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)\n    foreach(print_message ${ARGV})\n      message(STATUS \"[hunter] ${print_message}\")\n    endforeach()\n  endif()\nendfunction()\n\nfunction(hunter_gate_status_debug)\n  if(HUNTER_STATUS_DEBUG)\n    foreach(print_message ${ARGV})\n      string(TIMESTAMP timestamp)\n      message(STATUS \"[hunter *** DEBUG *** ${timestamp}] ${print_message}\")\n    endforeach()\n  endif()\nendfunction()\n\nfunction(hunter_gate_error_page error_page)\n  message(\"------------------------------ ERROR ------------------------------\")\n  message(\"    ${HUNTER_ERROR_PAGE}/${error_page}.html\")\n  message(\"-------------------------------------------------------------------\")\n  message(\"\")\n  message(FATAL_ERROR \"\")\nendfunction()\n\nfunction(hunter_gate_internal_error)\n  message(\"\")\n  foreach(print_message ${ARGV})\n    message(\"[hunter ** INTERNAL **] ${print_message}\")\n  endforeach()\n  message(\"[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]\")\n  message(\"\")\n  hunter_gate_error_page(\"error.internal\")\nendfunction()\n\nfunction(hunter_gate_fatal_error)\n  cmake_parse_arguments(hunter \"\" \"ERROR_PAGE\" \"\" \"${ARGV}\")\n  if(\"${hunter_ERROR_PAGE}\" STREQUAL \"\")\n    hunter_gate_internal_error(\"Expected ERROR_PAGE\")\n  endif()\n  message(\"\")\n  foreach(x ${hunter_UNPARSED_ARGUMENTS})\n    message(\"[hunter ** FATAL ERROR **] ${x}\")\n  endforeach()\n  message(\"[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]\")\n  message(\"\")\n  hunter_gate_error_page(\"${hunter_ERROR_PAGE}\")\nendfunction()\n\nfunction(hunter_gate_user_error)\n  hunter_gate_fatal_error(${ARGV} ERROR_PAGE \"error.incorrect.input.data\")\nendfunction()\n\nfunction(hunter_gate_self root version sha1 result)\n  string(COMPARE EQUAL \"${root}\" \"\" is_bad)\n  if(is_bad)\n    hunter_gate_internal_error(\"root is empty\")\n  endif()\n\n  string(COMPARE EQUAL \"${version}\" \"\" is_bad)\n  if(is_bad)\n    hunter_gate_internal_error(\"version is empty\")\n  endif()\n\n  string(COMPARE EQUAL \"${sha1}\" \"\" is_bad)\n  if(is_bad)\n    hunter_gate_internal_error(\"sha1 is empty\")\n  endif()\n\n  string(SUBSTRING \"${sha1}\" 0 7 archive_id)\n\n  set(\n      hunter_self\n      \"${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked\"\n  )\n\n  set(\"${result}\" \"${hunter_self}\" PARENT_SCOPE)\nendfunction()\n\n# Set HUNTER_GATE_ROOT cmake variable to suitable value.\nfunction(hunter_gate_detect_root)\n  # Check CMake variable\n  string(COMPARE NOTEQUAL \"${HUNTER_ROOT}\" \"\" not_empty)\n  if(not_empty)\n    set(HUNTER_GATE_ROOT \"${HUNTER_ROOT}\" PARENT_SCOPE)\n    hunter_gate_status_debug(\"HUNTER_ROOT detected by cmake variable\")\n    return()\n  endif()\n\n  # Check environment variable\n  string(COMPARE NOTEQUAL \"$ENV{HUNTER_ROOT}\" \"\" not_empty)\n  if(not_empty)\n    set(HUNTER_GATE_ROOT \"$ENV{HUNTER_ROOT}\" PARENT_SCOPE)\n    hunter_gate_status_debug(\"HUNTER_ROOT detected by environment variable\")\n    return()\n  endif()\n\n  # Check HOME environment variable\n  string(COMPARE NOTEQUAL \"$ENV{HOME}\" \"\" result)\n  if(result)\n    set(HUNTER_GATE_ROOT \"$ENV{HOME}/.hunter\" PARENT_SCOPE)\n    hunter_gate_status_debug(\"HUNTER_ROOT set using HOME environment variable\")\n    return()\n  endif()\n\n  # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)\n  if(WIN32)\n    string(COMPARE NOTEQUAL \"$ENV{SYSTEMDRIVE}\" \"\" result)\n    if(result)\n      set(HUNTER_GATE_ROOT \"$ENV{SYSTEMDRIVE}/.hunter\" PARENT_SCOPE)\n      hunter_gate_status_debug(\n          \"HUNTER_ROOT set using SYSTEMDRIVE environment variable\"\n      )\n      return()\n    endif()\n\n    string(COMPARE NOTEQUAL \"$ENV{USERPROFILE}\" \"\" result)\n    if(result)\n      set(HUNTER_GATE_ROOT \"$ENV{USERPROFILE}/.hunter\" PARENT_SCOPE)\n      hunter_gate_status_debug(\n          \"HUNTER_ROOT set using USERPROFILE environment variable\"\n      )\n      return()\n    endif()\n  endif()\n\n  hunter_gate_fatal_error(\n      \"Can't detect HUNTER_ROOT\"\n      ERROR_PAGE \"error.detect.hunter.root\"\n  )\nendfunction()\n\nfunction(hunter_gate_download dir)\n  string(\n      COMPARE\n      NOTEQUAL\n      \"$ENV{HUNTER_DISABLE_AUTOINSTALL}\"\n      \"\"\n      disable_autoinstall\n  )\n  if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)\n    hunter_gate_fatal_error(\n        \"Hunter not found in '${dir}'\"\n        \"Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'\"\n        \"Settings:\"\n        \"  HUNTER_ROOT: ${HUNTER_GATE_ROOT}\"\n        \"  HUNTER_SHA1: ${HUNTER_GATE_SHA1}\"\n        ERROR_PAGE \"error.run.install\"\n    )\n  endif()\n  string(COMPARE EQUAL \"${dir}\" \"\" is_bad)\n  if(is_bad)\n    hunter_gate_internal_error(\"Empty 'dir' argument\")\n  endif()\n\n  string(COMPARE EQUAL \"${HUNTER_GATE_SHA1}\" \"\" is_bad)\n  if(is_bad)\n    hunter_gate_internal_error(\"HUNTER_GATE_SHA1 empty\")\n  endif()\n\n  string(COMPARE EQUAL \"${HUNTER_GATE_URL}\" \"\" is_bad)\n  if(is_bad)\n    hunter_gate_internal_error(\"HUNTER_GATE_URL empty\")\n  endif()\n\n  set(done_location \"${dir}/DONE\")\n  set(sha1_location \"${dir}/SHA1\")\n\n  set(build_dir \"${dir}/Build\")\n  set(cmakelists \"${dir}/CMakeLists.txt\")\n\n  hunter_gate_status_debug(\"Locking directory: ${dir}\")\n  file(LOCK \"${dir}\" DIRECTORY GUARD FUNCTION)\n  hunter_gate_status_debug(\"Lock done\")\n\n  if(EXISTS \"${done_location}\")\n    # while waiting for lock other instance can do all the job\n    hunter_gate_status_debug(\"File '${done_location}' found, skip install\")\n    return()\n  endif()\n\n  file(REMOVE_RECURSE \"${build_dir}\")\n  file(REMOVE_RECURSE \"${cmakelists}\")\n\n  file(MAKE_DIRECTORY \"${build_dir}\") # check directory permissions\n\n  # Disabling languages speeds up a little bit, reduces noise in the output\n  # and avoids path too long windows error\n  file(\n      WRITE\n      \"${cmakelists}\"\n      \"cmake_minimum_required(VERSION 3.2)\\n\"\n      \"project(HunterDownload LANGUAGES NONE)\\n\"\n      \"include(ExternalProject)\\n\"\n      \"ExternalProject_Add(\\n\"\n      \"    Hunter\\n\"\n      \"    URL\\n\"\n      \"    \\\"${HUNTER_GATE_URL}\\\"\\n\"\n      \"    URL_HASH\\n\"\n      \"    SHA1=${HUNTER_GATE_SHA1}\\n\"\n      \"    DOWNLOAD_DIR\\n\"\n      \"    \\\"${dir}\\\"\\n\"\n      \"    TLS_VERIFY\\n\"\n      \"    ${HUNTER_TLS_VERIFY}\\n\"\n      \"    SOURCE_DIR\\n\"\n      \"    \\\"${dir}/Unpacked\\\"\\n\"\n      \"    CONFIGURE_COMMAND\\n\"\n      \"    \\\"\\\"\\n\"\n      \"    BUILD_COMMAND\\n\"\n      \"    \\\"\\\"\\n\"\n      \"    INSTALL_COMMAND\\n\"\n      \"    \\\"\\\"\\n\"\n      \")\\n\"\n  )\n\n  if(HUNTER_STATUS_DEBUG)\n    set(logging_params \"\")\n  else()\n    set(logging_params OUTPUT_QUIET)\n  endif()\n\n  hunter_gate_status_debug(\"Run generate\")\n\n  # Need to add toolchain file too.\n  # Otherwise on Visual Studio + MDD this will fail with error:\n  # \"Could not find an appropriate version of the Windows 10 SDK installed on this machine\"\n  if(EXISTS \"${CMAKE_TOOLCHAIN_FILE}\")\n    get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE \"${CMAKE_TOOLCHAIN_FILE}\" ABSOLUTE)\n    set(toolchain_arg \"-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}\")\n  else()\n    # 'toolchain_arg' can't be empty\n    set(toolchain_arg \"-DCMAKE_TOOLCHAIN_FILE=\")\n  endif()\n\n  string(COMPARE EQUAL \"${CMAKE_MAKE_PROGRAM}\" \"\" no_make)\n  if(no_make)\n    set(make_arg \"\")\n  else()\n    # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM\n    set(make_arg \"-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}\")\n  endif()\n\n  execute_process(\n      COMMAND\n      \"${CMAKE_COMMAND}\"\n      \"-H${dir}\"\n      \"-B${build_dir}\"\n      \"-G${CMAKE_GENERATOR}\"\n      \"${toolchain_arg}\"\n      ${make_arg}\n      WORKING_DIRECTORY \"${dir}\"\n      RESULT_VARIABLE download_result\n      ${logging_params}\n  )\n\n  if(NOT download_result EQUAL 0)\n    hunter_gate_internal_error(\n        \"Configure project failed.\"\n        \"To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}\"\n        \"In directory ${dir}\"\n    )\n  endif()\n\n  hunter_gate_status_print(\n      \"Initializing Hunter workspace (${HUNTER_GATE_SHA1})\"\n      \"  ${HUNTER_GATE_URL}\"\n      \"  -> ${dir}\"\n  )\n  execute_process(\n      COMMAND \"${CMAKE_COMMAND}\" --build \"${build_dir}\"\n      WORKING_DIRECTORY \"${dir}\"\n      RESULT_VARIABLE download_result\n      ${logging_params}\n  )\n\n  if(NOT download_result EQUAL 0)\n    hunter_gate_internal_error(\"Build project failed\")\n  endif()\n\n  file(REMOVE_RECURSE \"${build_dir}\")\n  file(REMOVE_RECURSE \"${cmakelists}\")\n\n  file(WRITE \"${sha1_location}\" \"${HUNTER_GATE_SHA1}\")\n  file(WRITE \"${done_location}\" \"DONE\")\n\n  hunter_gate_status_debug(\"Finished\")\nendfunction()\n\n# Must be a macro so master file 'cmake/Hunter' can\n# apply all variables easily just by 'include' command\n# (otherwise PARENT_SCOPE magic needed)\nmacro(HunterGate)\n  if(HUNTER_GATE_DONE)\n    # variable HUNTER_GATE_DONE set explicitly for external project\n    # (see `hunter_download`)\n    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)\n  endif()\n\n  # First HunterGate command will init Hunter, others will be ignored\n  get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)\n\n  if(NOT HUNTER_ENABLED)\n    # Empty function to avoid error \"unknown function\"\n    function(hunter_add_package)\n    endfunction()\n\n    set(\n        _hunter_gate_disabled_mode_dir\n        \"${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode\"\n    )\n    if(EXISTS \"${_hunter_gate_disabled_mode_dir}\")\n      hunter_gate_status_debug(\n          \"Adding \\\"disabled-mode\\\" modules: ${_hunter_gate_disabled_mode_dir}\"\n      )\n      list(APPEND CMAKE_PREFIX_PATH \"${_hunter_gate_disabled_mode_dir}\")\n    endif()\n  elseif(_hunter_gate_done)\n    hunter_gate_status_debug(\"Secondary HunterGate (use old settings)\")\n    hunter_gate_self(\n        \"${HUNTER_CACHED_ROOT}\"\n        \"${HUNTER_VERSION}\"\n        \"${HUNTER_SHA1}\"\n        _hunter_self\n    )\n    include(\"${_hunter_self}/cmake/Hunter\")\n  else()\n    set(HUNTER_GATE_LOCATION \"${CMAKE_CURRENT_SOURCE_DIR}\")\n\n    string(COMPARE NOTEQUAL \"${PROJECT_NAME}\" \"\" _have_project_name)\n    if(_have_project_name)\n      hunter_gate_fatal_error(\n          \"Please set HunterGate *before* 'project' command. \"\n          \"Detected project: ${PROJECT_NAME}\"\n          ERROR_PAGE \"error.huntergate.before.project\"\n      )\n    endif()\n\n    cmake_parse_arguments(\n        HUNTER_GATE \"LOCAL\" \"URL;SHA1;GLOBAL;FILEPATH\" \"\" ${ARGV}\n    )\n\n    string(COMPARE EQUAL \"${HUNTER_GATE_SHA1}\" \"\" _empty_sha1)\n    string(COMPARE EQUAL \"${HUNTER_GATE_URL}\" \"\" _empty_url)\n    string(\n        COMPARE\n        NOTEQUAL\n        \"${HUNTER_GATE_UNPARSED_ARGUMENTS}\"\n        \"\"\n        _have_unparsed\n    )\n    string(COMPARE NOTEQUAL \"${HUNTER_GATE_GLOBAL}\" \"\" _have_global)\n    string(COMPARE NOTEQUAL \"${HUNTER_GATE_FILEPATH}\" \"\" _have_filepath)\n\n    if(_have_unparsed)\n      hunter_gate_user_error(\n          \"HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}\"\n      )\n    endif()\n    if(_empty_sha1)\n      hunter_gate_user_error(\"SHA1 suboption of HunterGate is mandatory\")\n    endif()\n    if(_empty_url)\n      hunter_gate_user_error(\"URL suboption of HunterGate is mandatory\")\n    endif()\n    if(_have_global)\n      if(HUNTER_GATE_LOCAL)\n        hunter_gate_user_error(\"Unexpected LOCAL (already has GLOBAL)\")\n      endif()\n      if(_have_filepath)\n        hunter_gate_user_error(\"Unexpected FILEPATH (already has GLOBAL)\")\n      endif()\n    endif()\n    if(HUNTER_GATE_LOCAL)\n      if(_have_global)\n        hunter_gate_user_error(\"Unexpected GLOBAL (already has LOCAL)\")\n      endif()\n      if(_have_filepath)\n        hunter_gate_user_error(\"Unexpected FILEPATH (already has LOCAL)\")\n      endif()\n    endif()\n    if(_have_filepath)\n      if(_have_global)\n        hunter_gate_user_error(\"Unexpected GLOBAL (already has FILEPATH)\")\n      endif()\n      if(HUNTER_GATE_LOCAL)\n        hunter_gate_user_error(\"Unexpected LOCAL (already has FILEPATH)\")\n      endif()\n    endif()\n\n    hunter_gate_detect_root() # set HUNTER_GATE_ROOT\n\n    # Beautify path, fix probable problems with windows path slashes\n    get_filename_component(\n        HUNTER_GATE_ROOT \"${HUNTER_GATE_ROOT}\" ABSOLUTE\n    )\n    hunter_gate_status_debug(\"HUNTER_ROOT: ${HUNTER_GATE_ROOT}\")\n    if(NOT HUNTER_ALLOW_SPACES_IN_PATH)\n      string(FIND \"${HUNTER_GATE_ROOT}\" \" \" _contain_spaces)\n      if(NOT _contain_spaces EQUAL -1)\n        hunter_gate_fatal_error(\n            \"HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces.\"\n            \"Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error\"\n            \"(Use at your own risk!)\"\n            ERROR_PAGE \"error.spaces.in.hunter.root\"\n        )\n      endif()\n    endif()\n\n    string(\n        REGEX\n        MATCH\n        \"[0-9]+\\\\.[0-9]+\\\\.[0-9]+[-_a-z0-9]*\"\n        HUNTER_GATE_VERSION\n        \"${HUNTER_GATE_URL}\"\n    )\n    string(COMPARE EQUAL \"${HUNTER_GATE_VERSION}\" \"\" _is_empty)\n    if(_is_empty)\n      set(HUNTER_GATE_VERSION \"unknown\")\n    endif()\n\n    hunter_gate_self(\n        \"${HUNTER_GATE_ROOT}\"\n        \"${HUNTER_GATE_VERSION}\"\n        \"${HUNTER_GATE_SHA1}\"\n        _hunter_self\n    )\n\n    set(_master_location \"${_hunter_self}/cmake/Hunter\")\n    get_filename_component(_archive_id_location \"${_hunter_self}/..\" ABSOLUTE)\n    set(_done_location \"${_archive_id_location}/DONE\")\n    set(_sha1_location \"${_archive_id_location}/SHA1\")\n\n    # Check Hunter already downloaded by HunterGate\n    if(NOT EXISTS \"${_done_location}\")\n      hunter_gate_download(\"${_archive_id_location}\")\n    endif()\n\n    if(NOT EXISTS \"${_done_location}\")\n      hunter_gate_internal_error(\"hunter_gate_download failed\")\n    endif()\n\n    if(NOT EXISTS \"${_sha1_location}\")\n      hunter_gate_internal_error(\"${_sha1_location} not found\")\n    endif()\n    file(READ \"${_sha1_location}\" _sha1_value)\n    string(COMPARE EQUAL \"${_sha1_value}\" \"${HUNTER_GATE_SHA1}\" _is_equal)\n    if(NOT _is_equal)\n      hunter_gate_internal_error(\n          \"Short SHA1 collision:\"\n          \"  ${_sha1_value} (from ${_sha1_location})\"\n          \"  ${HUNTER_GATE_SHA1} (HunterGate)\"\n      )\n    endif()\n    if(NOT EXISTS \"${_master_location}\")\n      hunter_gate_user_error(\n          \"Master file not found:\"\n          \"  ${_master_location}\"\n          \"try to update Hunter/HunterGate\"\n      )\n    endif()\n    include(\"${_master_location}\")\n    set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)\n  endif()\nendmacro()\n"
  },
  {
    "path": "cmake/hunter/cache.cmake",
    "content": "set(\n    HUNTER_CACHE_SERVERS\n    \"https://github.com/huntercache/main\"\n    CACHE\n    STRING\n    \"Default cache server\"\n)\n\nstring(COMPARE EQUAL \"$ENV{TRAVIS}\" \"true\" is_travis)\nstring(COMPARE EQUAL \"$ENV{APPVEYOR}\" \"True\" is_appveyor)\nstring(COMPARE EQUAL \"$ENV{GITHUB_USER_PASSWORD}\" \"\" password_is_empty)\n\nif((is_travis OR is_appveyor) AND NOT password_is_empty)\n  option(HUNTER_RUN_UPLOAD \"Upload cache binaries\" ON)\nendif()\n\nmessage(STATUS \"Travis: ${is_travis}\")\nmessage(STATUS \"GITHUB_USER_PASSWORD: $ENV{GITHUB_USER_PASSWORD}\")\nmessage(STATUS \"Password empty: ${password_is_empty}\")\nmessage(STATUS \"Hunter upload: ${HUNTER_RUN_UPLOAD}\")\n\nset(\n    HUNTER_PASSWORDS_PATH\n    \"${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/passwords.cmake\"\n    CACHE\n    FILEPATH\n    \"Hunter passwords\"\n)"
  },
  {
    "path": "cmake/hunter/passwords.cmake",
    "content": "# cmake/Hunter/passwords.cmake\n\nhunter_upload_password(\n    REPO_OWNER \"huntercache\"\n    REPO \"SoA\"\n    USERNAME \"Regrowth-Studios-Bot\"\n    PASSWORD \"$ENV{GITHUB_USER_PASSWORD}\"\n)"
  },
  {
    "path": "jenkins.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (c) 2014, Ruslan Baratov\n# All rights reserved.\n\n# https://github.com/ruslo/polly/wiki/Jenkins\n\nimport argparse\nimport hashlib\nimport os\nimport shutil\nimport subprocess\nimport sys\nimport tarfile\nimport tempfile\nimport time\n\ndef clear_except_download(hunter_root):\n  base_dir = os.path.join(hunter_root, '_Base')\n  if os.path.exists(base_dir):\n    print('Clearing directory: {}'.format(base_dir))\n    hunter_download_dir = os.path.join(base_dir, 'Download', 'Hunter')\n    if os.path.exists(hunter_download_dir):\n      shutil.rmtree(hunter_download_dir)\n    for filename in os.listdir(base_dir):\n      if filename != 'Download':\n        to_remove = os.path.join(base_dir, filename)\n        if os.name == 'nt':\n          # Fix \"path too long\" error\n          subprocess.check_call(['cmd', '/c', 'rmdir', to_remove, '/S', '/Q'])\n        else:\n          shutil.rmtree(to_remove)\n\ndef run():\n  parser = argparse.ArgumentParser(\"Testing script\")\n  parser.add_argument(\n      '--nocreate',\n      action='store_true',\n      help='Do not create Hunter archive (reusing old)'\n  )\n  parser.add_argument(\n      '--all-release',\n      action='store_true',\n      help='Release build type for all 3rd party packages'\n  )\n  parser.add_argument(\n      '--clear',\n      action='store_true',\n      help='Remove old testing directories'\n  )\n  parser.add_argument(\n      '--clear-except-download',\n      action='store_true',\n      help='Remove old testing directories except `Download` directory'\n  )\n  parser.add_argument(\n      '--disable-builds',\n      action='store_true',\n      help='Disable building of package (useful for checking package can be loaded from cache)'\n  )\n  parser.add_argument(\n      '--upload',\n      action='store_true',\n      help='Upload cache to server and run checks (clean up will be triggered, same as --clear-except-download)'\n  )\n\n  parsed_args = parser.parse_args()\n\n  if parsed_args.upload:\n    password = os.getenv('GITHUB_USER_PASSWORD')\n    if password is None:\n      sys.exit('Expected environment variable GITHUB_USER_PASSWORD on uploading')\n\n  cdir = os.getcwd()\n  hunter_root = cdir\n\n  toolchain = os.getenv('TOOLCHAIN')\n  if not toolchain:\n    sys.exit('Environment variable TOOLCHAIN is empty')\n\n  project_dir = os.getenv('PROJECT_DIR')\n  if not project_dir:\n    sys.exit('Expected environment variable PROJECT_DIR')\n\n  ci = os.getenv('TRAVIS') or os.getenv('APPVEYOR')\n  if (ci and toolchain == 'dummy'):\n    print('Skip build: CI dummy (workaround)')\n    sys.exit(0)\n\n  verbose = True\n  env_verbose = os.getenv('VERBOSE')\n  if env_verbose:\n    if env_verbose == '0':\n      verbose = False\n    elif env_verbose == '1':\n      verbose = True\n    else:\n      sys.exit(\n          'Environment variable VERBOSE: expected 0 or 1, got \"{}\"'.format(\n              env_verbose\n          )\n      )\n\n  project_dir = os.path.join(cdir, project_dir)\n  project_dir = os.path.normpath(project_dir)\n\n  testing_dir = os.path.join(os.getcwd(), '_testing')\n  if os.path.exists(testing_dir) and parsed_args.clear:\n    print('REMOVING: {}'.format(testing_dir))\n    shutil.rmtree(testing_dir)\n  os.makedirs(testing_dir, exist_ok=True)\n\n  if os.name == 'nt':\n    hunter_junctions = os.getenv('HUNTER_JUNCTIONS')\n    if hunter_junctions:\n      temp_dir = tempfile.mkdtemp(dir=hunter_junctions)\n      shutil.rmtree(temp_dir)\n      subprocess.check_output(\n          \"cmd /c mklink /J {} {}\".format(temp_dir, testing_dir)\n      )\n      testing_dir = temp_dir\n\n  hunter_url = os.path.join(testing_dir, 'hunter.tar.gz')\n\n  if parsed_args.nocreate:\n    if not os.path.exists(hunter_url):\n      sys.exit('Option `--nocreate` but no archive')\n  else:\n    arch = tarfile.open(hunter_url, 'w:gz')\n    arch.add('cmake')\n    arch.add('scripts')\n    arch.close()\n\n  hunter_sha1 = hashlib.sha1(open(hunter_url, 'rb').read()).hexdigest()\n\n  hunter_root = os.path.join(testing_dir, 'Hunter')\n\n  if parsed_args.clear_except_download:\n    clear_except_download(hunter_root)\n\n  if os.name == 'nt':\n    which = 'where'\n  else:\n    which = 'which'\n\n  polly_root = os.getenv('POLLY_ROOT')\n  if polly_root:\n    print('Using POLLY_ROOT: {}'.format(polly_root))\n    build_script = os.path.join(polly_root, 'bin', 'build.py')\n  else:\n    build_script = subprocess.check_output(\n        [which, 'build.py'], universal_newlines=True\n    ).split('\\n')[0]\n\n  if not os.path.exists(build_script):\n    sys.exit('Script not found: {}'.format(build_script))\n\n  print('Testing in: {}'.format(testing_dir))\n  os.chdir(testing_dir)\n\n  args = [\n      sys.executable,\n      build_script,\n      '--clear',\n      '--config',\n      'Release',\n      '--toolchain',\n      toolchain,\n      '--home',\n      project_dir,\n      '--fwd',\n      'CMAKE_POLICY_DEFAULT_CMP0069=NEW',\n      'HUNTER_SUPPRESS_LIST_OF_FILES=ON',\n      'HUNTER_ROOT={}'.format(hunter_root),\n      'TESTING_URL={}'.format(hunter_url),\n      'TESTING_SHA1={}'.format(hunter_sha1)\n  ]\n\n  if not parsed_args.nocreate:\n    args += ['HUNTER_RUN_INSTALL=ON']\n\n  if parsed_args.disable_builds:\n    args += ['HUNTER_DISABLE_BUILDS=ON']\n\n  if parsed_args.all_release:\n    args += ['HUNTER_CONFIGURATION_TYPES=Release']\n\n  if parsed_args.upload:\n    passwords = os.path.join(\n        cdir, 'maintenance', 'upload-password-template.cmake'\n    )\n    args += ['HUNTER_RUN_UPLOAD=ON']\n    args += ['HUNTER_PASSWORDS_PATH={}'.format(passwords)]\n\n  args += ['--verbose']\n  if not verbose:\n    args += ['--discard', '10']\n    args += ['--tail', '200']\n\n  print('Execute command: [')\n  for i in args:\n    print('  `{}`'.format(i))\n  print(']')\n\n  subprocess.check_call(args)\n\n  if parsed_args.upload:\n    seconds = 60\n    print(\n        'Wait for GitHub changes became visible ({} seconds)...'.format(seconds)\n    )\n    time.sleep(seconds)\n\n    print('Run sanity build')\n\n    clear_except_download(hunter_root)\n\n    # Sanity check - run build again with disabled building from sources\n    args = [\n        sys.executable,\n        build_script,\n        '--clear',\n        '--verbose',\n        '--config',\n        'Release',\n        '--toolchain',\n        toolchain,\n        '--home',\n        project_dir,\n        '--fwd',\n        'HUNTER_DISABLE_BUILDS=ON',\n        'HUNTER_USE_CACHE_SERVERS=ONLY',\n        'CMAKE_POLICY_DEFAULT_CMP0069=NEW',\n        'HUNTER_SUPPRESS_LIST_OF_FILES=ON',\n        'HUNTER_ROOT={}'.format(hunter_root),\n        'TESTING_URL={}'.format(hunter_url),\n        'TESTING_SHA1={}'.format(hunter_sha1)\n    ]\n    if not verbose:\n      args += ['--discard', '10']\n      args += ['--tail', '200']\n\n    print('Execute command: [')\n    for i in args:\n      print('  `{}`'.format(i))\n    print(']')\n\n    subprocess.check_call(args)\n\nif __name__ == \"__main__\":\n  run()"
  },
  {
    "path": "scripts/ShowPredefined.cpp",
    "content": "\n// This file generated automatically by `create-predefined-list.py` script.\n// * https://github.com/ruslo/hunter\n\n#define HUNTER_QUOTE(x) #x\n#define HUNTER_STRING(x) HUNTER_QUOTE(x)\n#define HUNTER_INFO(x) \\\n    \"__HUNTER_MACRO_CHECK_BEGIN__\" \\\n    \"#define \" #x \" \" HUNTER_STRING(x) \\\n    \"__HUNTER_MACRO_CHECK_END__\"\n\n#include <exception> // Check std library version\n\n#if defined(__ANDROID__)\n# include <android/api-level.h> // Header with __ANDROID_API__\n#endif\n\n#if defined(_MSC_VER)\n# include <SdkDdkVer.h> // Header with _WIN32_WINNT\n#endif\n\n#if defined(_ABI64)\n# pragma message(HUNTER_INFO(_ABI64))\n#endif\n\n#if defined(_ABIO32)\n# pragma message(HUNTER_INFO(_ABIO32))\n#endif\n\n#if defined(_AIX)\n# pragma message(HUNTER_INFO(_AIX))\n#endif\n\n#if defined(_AIX3)\n# pragma message(HUNTER_INFO(_AIX3))\n#endif\n\n#if defined(_AIX32)\n# pragma message(HUNTER_INFO(_AIX32))\n#endif\n\n#if defined(_AIX41)\n# pragma message(HUNTER_INFO(_AIX41))\n#endif\n\n#if defined(_AIX43)\n# pragma message(HUNTER_INFO(_AIX43))\n#endif\n\n#if defined(_ARCH_601)\n# pragma message(HUNTER_INFO(_ARCH_601))\n#endif\n\n#if defined(_ARCH_603)\n# pragma message(HUNTER_INFO(_ARCH_603))\n#endif\n\n#if defined(_ARCH_PPC)\n# pragma message(HUNTER_INFO(_ARCH_PPC))\n#endif\n\n#if defined(_ARCH_PWR)\n# pragma message(HUNTER_INFO(_ARCH_PWR))\n#endif\n\n#if defined(_ARCH_PWR2)\n# pragma message(HUNTER_INFO(_ARCH_PWR2))\n#endif\n\n#if defined(_ATL_VER)\n# pragma message(HUNTER_INFO(_ATL_VER))\n#endif\n\n#if defined(_BIG_ENDIAN)\n# pragma message(HUNTER_INFO(_BIG_ENDIAN))\n#endif\n\n#if defined(_BYTE_ORDER)\n# pragma message(HUNTER_INFO(_BYTE_ORDER))\n#endif\n\n#if defined(_CHAR_UNSIGNED)\n# pragma message(HUNTER_INFO(_CHAR_UNSIGNED))\n#endif\n\n#if defined(_COMPILER_VERSION)\n# pragma message(HUNTER_INFO(_COMPILER_VERSION))\n#endif\n\n#if defined(_CONTROL_FLOW_GUARD)\n# pragma message(HUNTER_INFO(_CONTROL_FLOW_GUARD))\n#endif\n\n#if defined(_CPPLIB_VER)\n# pragma message(HUNTER_INFO(_CPPLIB_VER))\n#endif\n\n#if defined(_CPPRTTI)\n# pragma message(HUNTER_INFO(_CPPRTTI))\n#endif\n\n#if defined(_CPPUNWIND)\n# pragma message(HUNTER_INFO(_CPPUNWIND))\n#endif\n\n#if defined(_DLL)\n# pragma message(HUNTER_INFO(_DLL))\n#endif\n\n#if defined(_GLIBCXX_USE_CXX11_ABI)\n# pragma message(HUNTER_INFO(_GLIBCXX_USE_CXX11_ABI))\n#endif\n\n#if defined(_GNU_SOURCE)\n# pragma message(HUNTER_INFO(_GNU_SOURCE))\n#endif\n\n#if defined(_IA64)\n# pragma message(HUNTER_INFO(_IA64))\n#endif\n\n#if defined(_IBMR2)\n# pragma message(HUNTER_INFO(_IBMR2))\n#endif\n\n#if defined(_INTEGRAL_MAX_BITS)\n# pragma message(HUNTER_INFO(_INTEGRAL_MAX_BITS))\n#endif\n\n#if defined(_ISO_VOLATILE)\n# pragma message(HUNTER_INFO(_ISO_VOLATILE))\n#endif\n\n#if defined(_KERNEL_MODE)\n# pragma message(HUNTER_INFO(_KERNEL_MODE))\n#endif\n\n#if defined(_LIBCPP_HAS_NO_ASAN)\n# pragma message(HUNTER_INFO(_LIBCPP_HAS_NO_ASAN))\n#endif\n\n#if defined(_LIBCPP_VERSION)\n# pragma message(HUNTER_INFO(_LIBCPP_VERSION))\n#endif\n\n#if defined(_LITTLE_ENDIAN)\n# pragma message(HUNTER_INFO(_LITTLE_ENDIAN))\n#endif\n\n#if defined(_LP64)\n# pragma message(HUNTER_INFO(_LP64))\n#endif\n\n#if defined(_MANAGED)\n# pragma message(HUNTER_INFO(_MANAGED))\n#endif\n\n#if defined(_MFC_VER)\n# pragma message(HUNTER_INFO(_MFC_VER))\n#endif\n\n#if defined(_MIPSEB)\n# pragma message(HUNTER_INFO(_MIPSEB))\n#endif\n\n#if defined(_MIPSEL)\n# pragma message(HUNTER_INFO(_MIPSEL))\n#endif\n\n#if defined(_MIPS_ISA_MIPS1)\n# pragma message(HUNTER_INFO(_MIPS_ISA_MIPS1))\n#endif\n\n#if defined(_MIPS_ISA_MIPS2)\n# pragma message(HUNTER_INFO(_MIPS_ISA_MIPS2))\n#endif\n\n#if defined(_MIPS_ISA_MIPS3)\n# pragma message(HUNTER_INFO(_MIPS_ISA_MIPS3))\n#endif\n\n#if defined(_MIPS_ISA_MIPS4)\n# pragma message(HUNTER_INFO(_MIPS_ISA_MIPS4))\n#endif\n\n#if defined(_MRI)\n# pragma message(HUNTER_INFO(_MRI))\n#endif\n\n#if defined(_MSC_BUILD)\n# pragma message(HUNTER_INFO(_MSC_BUILD))\n#endif\n\n#if defined(_MSC_EXTENSIONS)\n# pragma message(HUNTER_INFO(_MSC_EXTENSIONS))\n#endif\n\n#if defined(_MSC_FULL_VER)\n# pragma message(HUNTER_INFO(_MSC_FULL_VER))\n#endif\n\n#if defined(_MSC_VER)\n# pragma message(HUNTER_INFO(_MSC_VER))\n#endif\n\n#if defined(_MSVC_LANG)\n# pragma message(HUNTER_INFO(_MSVC_LANG))\n#endif\n\n#if defined(_MT)\n# pragma message(HUNTER_INFO(_MT))\n#endif\n\n#if defined(_M_ALPHA)\n# pragma message(HUNTER_INFO(_M_ALPHA))\n#endif\n\n#if defined(_M_AMD64)\n# pragma message(HUNTER_INFO(_M_AMD64))\n#endif\n\n#if defined(_M_ARM)\n# pragma message(HUNTER_INFO(_M_ARM))\n#endif\n\n#if defined(_M_ARM64)\n# pragma message(HUNTER_INFO(_M_ARM64))\n#endif\n\n#if defined(_M_ARM_ARMV7VE)\n# pragma message(HUNTER_INFO(_M_ARM_ARMV7VE))\n#endif\n\n#if defined(_M_ARM_FP)\n# pragma message(HUNTER_INFO(_M_ARM_FP))\n#endif\n\n#if defined(_M_CEE)\n# pragma message(HUNTER_INFO(_M_CEE))\n#endif\n\n#if defined(_M_CEE_PURE)\n# pragma message(HUNTER_INFO(_M_CEE_PURE))\n#endif\n\n#if defined(_M_CEE_SAFE)\n# pragma message(HUNTER_INFO(_M_CEE_SAFE))\n#endif\n\n#if defined(_M_FP_EXCEPT)\n# pragma message(HUNTER_INFO(_M_FP_EXCEPT))\n#endif\n\n#if defined(_M_FP_FAST)\n# pragma message(HUNTER_INFO(_M_FP_FAST))\n#endif\n\n#if defined(_M_FP_PRECISE)\n# pragma message(HUNTER_INFO(_M_FP_PRECISE))\n#endif\n\n#if defined(_M_FP_STRICT)\n# pragma message(HUNTER_INFO(_M_FP_STRICT))\n#endif\n\n#if defined(_M_IA64)\n# pragma message(HUNTER_INFO(_M_IA64))\n#endif\n\n#if defined(_M_IX86)\n# pragma message(HUNTER_INFO(_M_IX86))\n#endif\n\n#if defined(_M_IX86_FP)\n# pragma message(HUNTER_INFO(_M_IX86_FP))\n#endif\n\n#if defined(_M_PPC)\n# pragma message(HUNTER_INFO(_M_PPC))\n#endif\n\n#if defined(_M_X64)\n# pragma message(HUNTER_INFO(_M_X64))\n#endif\n\n#if defined(_NATIVE_WCHAR_T_DEFINED)\n# pragma message(HUNTER_INFO(_NATIVE_WCHAR_T_DEFINED))\n#endif\n\n#if defined(_NTO_VERSION)\n# pragma message(HUNTER_INFO(_NTO_VERSION))\n#endif\n\n#if defined(_OPENMP)\n# pragma message(HUNTER_INFO(_OPENMP))\n#endif\n\n#if defined(_PACC_VER)\n# pragma message(HUNTER_INFO(_PACC_VER))\n#endif\n\n#if defined(_PA_RISC1_0)\n# pragma message(HUNTER_INFO(_PA_RISC1_0))\n#endif\n\n#if defined(_PA_RISC1_1)\n# pragma message(HUNTER_INFO(_PA_RISC1_1))\n#endif\n\n#if defined(_PA_RISC2_0)\n# pragma message(HUNTER_INFO(_PA_RISC2_0))\n#endif\n\n#if defined(_PDP_ENDIAN)\n# pragma message(HUNTER_INFO(_PDP_ENDIAN))\n#endif\n\n#if defined(_POSIX_SOURCE)\n# pragma message(HUNTER_INFO(_POSIX_SOURCE))\n#endif\n\n#if defined(_POWER)\n# pragma message(HUNTER_INFO(_POWER))\n#endif\n\n#if defined(_PREFAST_)\n# pragma message(HUNTER_INFO(_PREFAST_))\n#endif\n\n#if defined(_R3000)\n# pragma message(HUNTER_INFO(_R3000))\n#endif\n\n#if defined(_R4000)\n# pragma message(HUNTER_INFO(_R4000))\n#endif\n\n#if defined(_RWSTD_VER)\n# pragma message(HUNTER_INFO(_RWSTD_VER))\n#endif\n\n#if defined(_SGI_COMPILER_VERSION)\n# pragma message(HUNTER_INFO(_SGI_COMPILER_VERSION))\n#endif\n\n#if defined(_STDC_PREDEF_H)\n# pragma message(HUNTER_INFO(_STDC_PREDEF_H))\n#endif\n\n#if defined(_STLPORT_MAJOR)\n# pragma message(HUNTER_INFO(_STLPORT_MAJOR))\n#endif\n\n#if defined(_STLPORT_VERSION)\n# pragma message(HUNTER_INFO(_STLPORT_VERSION))\n#endif\n\n#if defined(_SYSTYPE_BSD)\n# pragma message(HUNTER_INFO(_SYSTYPE_BSD))\n#endif\n\n#if defined(_SYSTYPE_SVR4)\n# pragma message(HUNTER_INFO(_SYSTYPE_SVR4))\n#endif\n\n#if defined(_VC_NODEFAULTLIB)\n# pragma message(HUNTER_INFO(_VC_NODEFAULTLIB))\n#endif\n\n#if defined(_WCHAR_T_DEFINED)\n# pragma message(HUNTER_INFO(_WCHAR_T_DEFINED))\n#endif\n\n#if defined(_WIN32)\n# pragma message(HUNTER_INFO(_WIN32))\n#endif\n\n#if defined(_WIN32_WINNT)\n# pragma message(HUNTER_INFO(_WIN32_WINNT))\n#endif\n\n#if defined(_WIN64)\n# pragma message(HUNTER_INFO(_WIN64))\n#endif\n\n#if defined(_WINRT_DLL)\n# pragma message(HUNTER_INFO(_WINRT_DLL))\n#endif\n\n#if defined(_Wp64)\n# pragma message(HUNTER_INFO(_Wp64))\n#endif\n\n#if defined(_X86_)\n# pragma message(HUNTER_INFO(_X86_))\n#endif\n\n#if defined(_XENON)\n# pragma message(HUNTER_INFO(_XENON))\n#endif\n\n#if defined(_XOPEN_SOURCE)\n# pragma message(HUNTER_INFO(_XOPEN_SOURCE))\n#endif\n\n#if defined(_YVALS)\n# pragma message(HUNTER_INFO(_YVALS))\n#endif\n\n#if defined(__370__)\n# pragma message(HUNTER_INFO(__370__))\n#endif\n\n#if defined(__AARCH64EB__)\n# pragma message(HUNTER_INFO(__AARCH64EB__))\n#endif\n\n#if defined(__AARCH64EL__)\n# pragma message(HUNTER_INFO(__AARCH64EL__))\n#endif\n\n#if defined(__AARCH64_SIMD__)\n# pragma message(HUNTER_INFO(__AARCH64_SIMD__))\n#endif\n\n#if defined(__ACCUM_EPSILON__)\n# pragma message(HUNTER_INFO(__ACCUM_EPSILON__))\n#endif\n\n#if defined(__ACCUM_FBIT__)\n# pragma message(HUNTER_INFO(__ACCUM_FBIT__))\n#endif\n\n#if defined(__ACCUM_IBIT__)\n# pragma message(HUNTER_INFO(__ACCUM_IBIT__))\n#endif\n\n#if defined(__ACCUM_MAX__)\n# pragma message(HUNTER_INFO(__ACCUM_MAX__))\n#endif\n\n#if defined(__ACCUM_MIN__)\n# pragma message(HUNTER_INFO(__ACCUM_MIN__))\n#endif\n\n#if defined(__ALTIVEC__)\n# pragma message(HUNTER_INFO(__ALTIVEC__))\n#endif\n\n#if defined(__ANDROID_API__)\n# pragma message(HUNTER_INFO(__ANDROID_API__))\n#endif\n\n#if defined(__ANDROID__)\n# pragma message(HUNTER_INFO(__ANDROID__))\n#endif\n\n#if defined(__APCS_32__)\n# pragma message(HUNTER_INFO(__APCS_32__))\n#endif\n\n#if defined(__APPLE_CC__)\n# pragma message(HUNTER_INFO(__APPLE_CC__))\n#endif\n\n#if defined(__APPLE__)\n# pragma message(HUNTER_INFO(__APPLE__))\n#endif\n\n#if defined(__ARM64_ARCH_8__)\n# pragma message(HUNTER_INFO(__ARM64_ARCH_8__))\n#endif\n\n#if defined(__ARMEB__)\n# pragma message(HUNTER_INFO(__ARMEB__))\n#endif\n\n#if defined(__ARMEL__)\n# pragma message(HUNTER_INFO(__ARMEL__))\n#endif\n\n#if defined(__ARM_32BIT_STATE)\n# pragma message(HUNTER_INFO(__ARM_32BIT_STATE))\n#endif\n\n#if defined(__ARM_64BIT_STATE)\n# pragma message(HUNTER_INFO(__ARM_64BIT_STATE))\n#endif\n\n#if defined(__ARM_ACLE)\n# pragma message(HUNTER_INFO(__ARM_ACLE))\n#endif\n\n#if defined(__ARM_ALIGN_MAX_STACK_PWR)\n# pragma message(HUNTER_INFO(__ARM_ALIGN_MAX_STACK_PWR))\n#endif\n\n#if defined(__ARM_ARCH)\n# pragma message(HUNTER_INFO(__ARM_ARCH))\n#endif\n\n#if defined(__ARM_ARCH_7A__)\n# pragma message(HUNTER_INFO(__ARM_ARCH_7A__))\n#endif\n\n#if defined(__ARM_ARCH_7S__)\n# pragma message(HUNTER_INFO(__ARM_ARCH_7S__))\n#endif\n\n#if defined(__ARM_ARCH_EXT_IDIV__)\n# pragma message(HUNTER_INFO(__ARM_ARCH_EXT_IDIV__))\n#endif\n\n#if defined(__ARM_ARCH_ISA_A64)\n# pragma message(HUNTER_INFO(__ARM_ARCH_ISA_A64))\n#endif\n\n#if defined(__ARM_ARCH_ISA_ARM)\n# pragma message(HUNTER_INFO(__ARM_ARCH_ISA_ARM))\n#endif\n\n#if defined(__ARM_ARCH_ISA_THUMB)\n# pragma message(HUNTER_INFO(__ARM_ARCH_ISA_THUMB))\n#endif\n\n#if defined(__ARM_ARCH_PROFILE)\n# pragma message(HUNTER_INFO(__ARM_ARCH_PROFILE))\n#endif\n\n#if defined(__ARM_ASM_SYNTAX_UNIFIED__)\n# pragma message(HUNTER_INFO(__ARM_ASM_SYNTAX_UNIFIED__))\n#endif\n\n#if defined(__ARM_EABI__)\n# pragma message(HUNTER_INFO(__ARM_EABI__))\n#endif\n\n#if defined(__ARM_FEATURE_CLZ)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_CLZ))\n#endif\n\n#if defined(__ARM_FEATURE_CRYPTO)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_CRYPTO))\n#endif\n\n#if defined(__ARM_FEATURE_DIV)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_DIV))\n#endif\n\n#if defined(__ARM_FEATURE_DSP)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_DSP))\n#endif\n\n#if defined(__ARM_FEATURE_FMA)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_FMA))\n#endif\n\n#if defined(__ARM_FEATURE_LDREX)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_LDREX))\n#endif\n\n#if defined(__ARM_FEATURE_QBIT)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_QBIT))\n#endif\n\n#if defined(__ARM_FEATURE_SAT)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_SAT))\n#endif\n\n#if defined(__ARM_FEATURE_SIMD32)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_SIMD32))\n#endif\n\n#if defined(__ARM_FEATURE_UNALIGNED)\n# pragma message(HUNTER_INFO(__ARM_FEATURE_UNALIGNED))\n#endif\n\n#if defined(__ARM_FP)\n# pragma message(HUNTER_INFO(__ARM_FP))\n#endif\n\n#if defined(__ARM_FP16_FORMAT_IEEE)\n# pragma message(HUNTER_INFO(__ARM_FP16_FORMAT_IEEE))\n#endif\n\n#if defined(__ARM_NEON)\n# pragma message(HUNTER_INFO(__ARM_NEON))\n#endif\n\n#if defined(__ARM_NEON_FP)\n# pragma message(HUNTER_INFO(__ARM_NEON_FP))\n#endif\n\n#if defined(__ARM_NEON__)\n# pragma message(HUNTER_INFO(__ARM_NEON__))\n#endif\n\n#if defined(__ARM_PCS_AAPCS64)\n# pragma message(HUNTER_INFO(__ARM_PCS_AAPCS64))\n#endif\n\n#if defined(__ARM_PCS_VFP)\n# pragma message(HUNTER_INFO(__ARM_PCS_VFP))\n#endif\n\n#if defined(__ARM_SIZEOF_MINIMAL_ENUM)\n# pragma message(HUNTER_INFO(__ARM_SIZEOF_MINIMAL_ENUM))\n#endif\n\n#if defined(__ARM_SIZEOF_WCHAR_T)\n# pragma message(HUNTER_INFO(__ARM_SIZEOF_WCHAR_T))\n#endif\n\n#if defined(__ARM_VFPV3__)\n# pragma message(HUNTER_INFO(__ARM_VFPV3__))\n#endif\n\n#if defined(__ARM_VFPV4__)\n# pragma message(HUNTER_INFO(__ARM_VFPV4__))\n#endif\n\n#if defined(__ATOMIC_ACQUIRE)\n# pragma message(HUNTER_INFO(__ATOMIC_ACQUIRE))\n#endif\n\n#if defined(__ATOMIC_ACQ_REL)\n# pragma message(HUNTER_INFO(__ATOMIC_ACQ_REL))\n#endif\n\n#if defined(__ATOMIC_CONSUME)\n# pragma message(HUNTER_INFO(__ATOMIC_CONSUME))\n#endif\n\n#if defined(__ATOMIC_HLE_ACQUIRE)\n# pragma message(HUNTER_INFO(__ATOMIC_HLE_ACQUIRE))\n#endif\n\n#if defined(__ATOMIC_HLE_RELEASE)\n# pragma message(HUNTER_INFO(__ATOMIC_HLE_RELEASE))\n#endif\n\n#if defined(__ATOMIC_RELAXED)\n# pragma message(HUNTER_INFO(__ATOMIC_RELAXED))\n#endif\n\n#if defined(__ATOMIC_RELEASE)\n# pragma message(HUNTER_INFO(__ATOMIC_RELEASE))\n#endif\n\n#if defined(__ATOMIC_SEQ_CST)\n# pragma message(HUNTER_INFO(__ATOMIC_SEQ_CST))\n#endif\n\n#if defined(__ATOM__)\n# pragma message(HUNTER_INFO(__ATOM__))\n#endif\n\n#if defined(__AVX2__)\n# pragma message(HUNTER_INFO(__AVX2__))\n#endif\n\n#if defined(__AVX__)\n# pragma message(HUNTER_INFO(__AVX__))\n#endif\n\n#if defined(__BEOS__)\n# pragma message(HUNTER_INFO(__BEOS__))\n#endif\n\n#if defined(__BFIN__)\n# pragma message(HUNTER_INFO(__BFIN__))\n#endif\n\n#if defined(__BIGGEST_ALIGNMENT__)\n# pragma message(HUNTER_INFO(__BIGGEST_ALIGNMENT__))\n#endif\n\n#if defined(__BIG_ENDIAN)\n# pragma message(HUNTER_INFO(__BIG_ENDIAN))\n#endif\n\n#if defined(__BIG_ENDIAN__)\n# pragma message(HUNTER_INFO(__BIG_ENDIAN__))\n#endif\n\n#if defined(__BLOCKS__)\n# pragma message(HUNTER_INFO(__BLOCKS__))\n#endif\n\n#if defined(__BORLANDC__)\n# pragma message(HUNTER_INFO(__BORLANDC__))\n#endif\n\n#if defined(__BYTE_ORDER)\n# pragma message(HUNTER_INFO(__BYTE_ORDER))\n#endif\n\n#if defined(__BYTE_ORDER__)\n# pragma message(HUNTER_INFO(__BYTE_ORDER__))\n#endif\n\n#if defined(__CHAR16_TYPE__)\n# pragma message(HUNTER_INFO(__CHAR16_TYPE__))\n#endif\n\n#if defined(__CHAR32_TYPE__)\n# pragma message(HUNTER_INFO(__CHAR32_TYPE__))\n#endif\n\n#if defined(__CHAR_BIT__)\n# pragma message(HUNTER_INFO(__CHAR_BIT__))\n#endif\n\n#if defined(__CHAR_UNSIGNED__)\n# pragma message(HUNTER_INFO(__CHAR_UNSIGNED__))\n#endif\n\n#if defined(__CLR_VER)\n# pragma message(HUNTER_INFO(__CLR_VER))\n#endif\n\n#if defined(__CODEGEARC__)\n# pragma message(HUNTER_INFO(__CODEGEARC__))\n#endif\n\n#if defined(__COMO_VERSION__)\n# pragma message(HUNTER_INFO(__COMO_VERSION__))\n#endif\n\n#if defined(__COMO__)\n# pragma message(HUNTER_INFO(__COMO__))\n#endif\n\n#if defined(__COMPILER_VER__)\n# pragma message(HUNTER_INFO(__COMPILER_VER__))\n#endif\n\n#if defined(__CONO_VERSION__)\n# pragma message(HUNTER_INFO(__CONO_VERSION__))\n#endif\n\n#if defined(__CONSTANT_CFSTRINGS__)\n# pragma message(HUNTER_INFO(__CONSTANT_CFSTRINGS__))\n#endif\n\n#if defined(__COUNTER__)\n# pragma message(HUNTER_INFO(__COUNTER__))\n#endif\n\n#if defined(__CRTL_VER)\n# pragma message(HUNTER_INFO(__CRTL_VER))\n#endif\n\n#if defined(__CWCC__)\n# pragma message(HUNTER_INFO(__CWCC__))\n#endif\n\n#if defined(__CYGWIN__)\n# pragma message(HUNTER_INFO(__CYGWIN__))\n#endif\n\n#if defined(__DA_FBIT__)\n# pragma message(HUNTER_INFO(__DA_FBIT__))\n#endif\n\n#if defined(__DA_IBIT__)\n# pragma message(HUNTER_INFO(__DA_IBIT__))\n#endif\n\n#if defined(__DBL_DECIMAL_DIG__)\n# pragma message(HUNTER_INFO(__DBL_DECIMAL_DIG__))\n#endif\n\n#if defined(__DBL_DENORM_MIN__)\n# pragma message(HUNTER_INFO(__DBL_DENORM_MIN__))\n#endif\n\n#if defined(__DBL_DIG__)\n# pragma message(HUNTER_INFO(__DBL_DIG__))\n#endif\n\n#if defined(__DBL_EPSILON__)\n# pragma message(HUNTER_INFO(__DBL_EPSILON__))\n#endif\n\n#if defined(__DBL_HAS_DENORM__)\n# pragma message(HUNTER_INFO(__DBL_HAS_DENORM__))\n#endif\n\n#if defined(__DBL_HAS_INFINITY__)\n# pragma message(HUNTER_INFO(__DBL_HAS_INFINITY__))\n#endif\n\n#if defined(__DBL_HAS_QUIET_NAN__)\n# pragma message(HUNTER_INFO(__DBL_HAS_QUIET_NAN__))\n#endif\n\n#if defined(__DBL_MANT_DIG__)\n# pragma message(HUNTER_INFO(__DBL_MANT_DIG__))\n#endif\n\n#if defined(__DBL_MAX_10_EXP__)\n# pragma message(HUNTER_INFO(__DBL_MAX_10_EXP__))\n#endif\n\n#if defined(__DBL_MAX_EXP__)\n# pragma message(HUNTER_INFO(__DBL_MAX_EXP__))\n#endif\n\n#if defined(__DBL_MAX__)\n# pragma message(HUNTER_INFO(__DBL_MAX__))\n#endif\n\n#if defined(__DBL_MIN_10_EXP__)\n# pragma message(HUNTER_INFO(__DBL_MIN_10_EXP__))\n#endif\n\n#if defined(__DBL_MIN_EXP__)\n# pragma message(HUNTER_INFO(__DBL_MIN_EXP__))\n#endif\n\n#if defined(__DBL_MIN__)\n# pragma message(HUNTER_INFO(__DBL_MIN__))\n#endif\n\n#if defined(__DCC__)\n# pragma message(HUNTER_INFO(__DCC__))\n#endif\n\n#if defined(__DEC128_EPSILON__)\n# pragma message(HUNTER_INFO(__DEC128_EPSILON__))\n#endif\n\n#if defined(__DEC128_MANT_DIG__)\n# pragma message(HUNTER_INFO(__DEC128_MANT_DIG__))\n#endif\n\n#if defined(__DEC128_MAX_EXP__)\n# pragma message(HUNTER_INFO(__DEC128_MAX_EXP__))\n#endif\n\n#if defined(__DEC128_MAX__)\n# pragma message(HUNTER_INFO(__DEC128_MAX__))\n#endif\n\n#if defined(__DEC128_MIN_EXP__)\n# pragma message(HUNTER_INFO(__DEC128_MIN_EXP__))\n#endif\n\n#if defined(__DEC128_MIN__)\n# pragma message(HUNTER_INFO(__DEC128_MIN__))\n#endif\n\n#if defined(__DEC128_SUBNORMAL_MIN__)\n# pragma message(HUNTER_INFO(__DEC128_SUBNORMAL_MIN__))\n#endif\n\n#if defined(__DEC32_EPSILON__)\n# pragma message(HUNTER_INFO(__DEC32_EPSILON__))\n#endif\n\n#if defined(__DEC32_MANT_DIG__)\n# pragma message(HUNTER_INFO(__DEC32_MANT_DIG__))\n#endif\n\n#if defined(__DEC32_MAX_EXP__)\n# pragma message(HUNTER_INFO(__DEC32_MAX_EXP__))\n#endif\n\n#if defined(__DEC32_MAX__)\n# pragma message(HUNTER_INFO(__DEC32_MAX__))\n#endif\n\n#if defined(__DEC32_MIN_EXP__)\n# pragma message(HUNTER_INFO(__DEC32_MIN_EXP__))\n#endif\n\n#if defined(__DEC32_MIN__)\n# pragma message(HUNTER_INFO(__DEC32_MIN__))\n#endif\n\n#if defined(__DEC32_SUBNORMAL_MIN__)\n# pragma message(HUNTER_INFO(__DEC32_SUBNORMAL_MIN__))\n#endif\n\n#if defined(__DEC64_EPSILON__)\n# pragma message(HUNTER_INFO(__DEC64_EPSILON__))\n#endif\n\n#if defined(__DEC64_MANT_DIG__)\n# pragma message(HUNTER_INFO(__DEC64_MANT_DIG__))\n#endif\n\n#if defined(__DEC64_MAX_EXP__)\n# pragma message(HUNTER_INFO(__DEC64_MAX_EXP__))\n#endif\n\n#if defined(__DEC64_MAX__)\n# pragma message(HUNTER_INFO(__DEC64_MAX__))\n#endif\n\n#if defined(__DEC64_MIN_EXP__)\n# pragma message(HUNTER_INFO(__DEC64_MIN_EXP__))\n#endif\n\n#if defined(__DEC64_MIN__)\n# pragma message(HUNTER_INFO(__DEC64_MIN__))\n#endif\n\n#if defined(__DEC64_SUBNORMAL_MIN__)\n# pragma message(HUNTER_INFO(__DEC64_SUBNORMAL_MIN__))\n#endif\n\n#if defined(__DECC)\n# pragma message(HUNTER_INFO(__DECC))\n#endif\n\n#if defined(__DECCXX)\n# pragma message(HUNTER_INFO(__DECCXX))\n#endif\n\n#if defined(__DECCXX_VER)\n# pragma message(HUNTER_INFO(__DECCXX_VER))\n#endif\n\n#if defined(__DECC_VER)\n# pragma message(HUNTER_INFO(__DECC_VER))\n#endif\n\n#if defined(__DECIMAL_BID_FORMAT__)\n# pragma message(HUNTER_INFO(__DECIMAL_BID_FORMAT__))\n#endif\n\n#if defined(__DECIMAL_DIG__)\n# pragma message(HUNTER_INFO(__DECIMAL_DIG__))\n#endif\n\n#if defined(__DEC_EVAL_METHOD__)\n# pragma message(HUNTER_INFO(__DEC_EVAL_METHOD__))\n#endif\n\n#if defined(__DEPRECATED)\n# pragma message(HUNTER_INFO(__DEPRECATED))\n#endif\n\n#if defined(__DMC__)\n# pragma message(HUNTER_INFO(__DMC__))\n#endif\n\n#if defined(__DQ_FBIT__)\n# pragma message(HUNTER_INFO(__DQ_FBIT__))\n#endif\n\n#if defined(__DQ_IBIT__)\n# pragma message(HUNTER_INFO(__DQ_IBIT__))\n#endif\n\n#if defined(__DYNAMIC__)\n# pragma message(HUNTER_INFO(__DYNAMIC__))\n#endif\n\n#if defined(__DragonFly__)\n# pragma message(HUNTER_INFO(__DragonFly__))\n#endif\n\n#if defined(__ECC)\n# pragma message(HUNTER_INFO(__ECC))\n#endif\n\n#if defined(__EDG__)\n# pragma message(HUNTER_INFO(__EDG__))\n#endif\n\n#if defined(__ELF__)\n# pragma message(HUNTER_INFO(__ELF__))\n#endif\n\n#if defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)\n# pragma message(HUNTER_INFO(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__))\n#endif\n\n#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)\n# pragma message(HUNTER_INFO(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__))\n#endif\n\n#if defined(__EXCEPTIONS)\n# pragma message(HUNTER_INFO(__EXCEPTIONS))\n#endif\n\n#if defined(__FINITE_MATH_ONLY__)\n# pragma message(HUNTER_INFO(__FINITE_MATH_ONLY__))\n#endif\n\n#if defined(__FLOAT_WORD_ORDER__)\n# pragma message(HUNTER_INFO(__FLOAT_WORD_ORDER__))\n#endif\n\n#if defined(__FLT_DECIMAL_DIG__)\n# pragma message(HUNTER_INFO(__FLT_DECIMAL_DIG__))\n#endif\n\n#if defined(__FLT_DENORM_MIN__)\n# pragma message(HUNTER_INFO(__FLT_DENORM_MIN__))\n#endif\n\n#if defined(__FLT_DIG__)\n# pragma message(HUNTER_INFO(__FLT_DIG__))\n#endif\n\n#if defined(__FLT_EPSILON__)\n# pragma message(HUNTER_INFO(__FLT_EPSILON__))\n#endif\n\n#if defined(__FLT_EVAL_METHOD__)\n# pragma message(HUNTER_INFO(__FLT_EVAL_METHOD__))\n#endif\n\n#if defined(__FLT_HAS_DENORM__)\n# pragma message(HUNTER_INFO(__FLT_HAS_DENORM__))\n#endif\n\n#if defined(__FLT_HAS_INFINITY__)\n# pragma message(HUNTER_INFO(__FLT_HAS_INFINITY__))\n#endif\n\n#if defined(__FLT_HAS_QUIET_NAN__)\n# pragma message(HUNTER_INFO(__FLT_HAS_QUIET_NAN__))\n#endif\n\n#if defined(__FLT_MANT_DIG__)\n# pragma message(HUNTER_INFO(__FLT_MANT_DIG__))\n#endif\n\n#if defined(__FLT_MAX_10_EXP__)\n# pragma message(HUNTER_INFO(__FLT_MAX_10_EXP__))\n#endif\n\n#if defined(__FLT_MAX_EXP__)\n# pragma message(HUNTER_INFO(__FLT_MAX_EXP__))\n#endif\n\n#if defined(__FLT_MAX__)\n# pragma message(HUNTER_INFO(__FLT_MAX__))\n#endif\n\n#if defined(__FLT_MIN_10_EXP__)\n# pragma message(HUNTER_INFO(__FLT_MIN_10_EXP__))\n#endif\n\n#if defined(__FLT_MIN_EXP__)\n# pragma message(HUNTER_INFO(__FLT_MIN_EXP__))\n#endif\n\n#if defined(__FLT_MIN__)\n# pragma message(HUNTER_INFO(__FLT_MIN__))\n#endif\n\n#if defined(__FLT_RADIX__)\n# pragma message(HUNTER_INFO(__FLT_RADIX__))\n#endif\n\n#if defined(__FMA4__)\n# pragma message(HUNTER_INFO(__FMA4__))\n#endif\n\n#if defined(__FMA__)\n# pragma message(HUNTER_INFO(__FMA__))\n#endif\n\n#if defined(__FP_FAST_FMA)\n# pragma message(HUNTER_INFO(__FP_FAST_FMA))\n#endif\n\n#if defined(__FP_FAST_FMAF)\n# pragma message(HUNTER_INFO(__FP_FAST_FMAF))\n#endif\n\n#if defined(__FP_FAST_FMAL)\n# pragma message(HUNTER_INFO(__FP_FAST_FMAL))\n#endif\n\n#if defined(__FRACT_EPSILON__)\n# pragma message(HUNTER_INFO(__FRACT_EPSILON__))\n#endif\n\n#if defined(__FRACT_FBIT__)\n# pragma message(HUNTER_INFO(__FRACT_FBIT__))\n#endif\n\n#if defined(__FRACT_IBIT__)\n# pragma message(HUNTER_INFO(__FRACT_IBIT__))\n#endif\n\n#if defined(__FRACT_MAX__)\n# pragma message(HUNTER_INFO(__FRACT_MAX__))\n#endif\n\n#if defined(__FRACT_MIN__)\n# pragma message(HUNTER_INFO(__FRACT_MIN__))\n#endif\n\n#if defined(__FUNCDNAME__)\n# pragma message(HUNTER_INFO(__FUNCDNAME__))\n#endif\n\n#if defined(__FUNCSIG__)\n# pragma message(HUNTER_INFO(__FUNCSIG__))\n#endif\n\n#if defined(__FXSR__)\n# pragma message(HUNTER_INFO(__FXSR__))\n#endif\n\n#if defined(__FreeBSD__)\n# pragma message(HUNTER_INFO(__FreeBSD__))\n#endif\n\n#if defined(__FreeBSD_version)\n# pragma message(HUNTER_INFO(__FreeBSD_version))\n#endif\n\n#if defined(__GCCXML__)\n# pragma message(HUNTER_INFO(__GCCXML__))\n#endif\n\n#if defined(__GCC_ASM_FLAG_OUTPUTS__)\n# pragma message(HUNTER_INFO(__GCC_ASM_FLAG_OUTPUTS__))\n#endif\n\n#if defined(__GCC_ATOMIC_BOOL_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_BOOL_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_CHAR16_T_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_CHAR16_T_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_CHAR32_T_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_CHAR32_T_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_CHAR_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_CHAR_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_INT_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_INT_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_LLONG_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_LLONG_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_LONG_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_LONG_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_POINTER_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_POINTER_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_SHORT_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_SHORT_LOCK_FREE))\n#endif\n\n#if defined(__GCC_ATOMIC_TEST_AND_SET_TRUEVAL)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_TEST_AND_SET_TRUEVAL))\n#endif\n\n#if defined(__GCC_ATOMIC_WCHAR_T_LOCK_FREE)\n# pragma message(HUNTER_INFO(__GCC_ATOMIC_WCHAR_T_LOCK_FREE))\n#endif\n\n#if defined(__GCC_HAVE_DWARF2_CFI_ASM)\n# pragma message(HUNTER_INFO(__GCC_HAVE_DWARF2_CFI_ASM))\n#endif\n\n#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1)\n# pragma message(HUNTER_INFO(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1))\n#endif\n\n#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)\n# pragma message(HUNTER_INFO(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16))\n#endif\n\n#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)\n# pragma message(HUNTER_INFO(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2))\n#endif\n\n#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)\n# pragma message(HUNTER_INFO(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))\n#endif\n\n#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\n# pragma message(HUNTER_INFO(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8))\n#endif\n\n#if defined(__GCC_IEC_559)\n# pragma message(HUNTER_INFO(__GCC_IEC_559))\n#endif\n\n#if defined(__GCC_IEC_559_COMPLEX)\n# pragma message(HUNTER_INFO(__GCC_IEC_559_COMPLEX))\n#endif\n\n#if defined(__GHS_VERSION_NUMBER__)\n# pragma message(HUNTER_INFO(__GHS_VERSION_NUMBER__))\n#endif\n\n#if defined(__GLIBCPP__)\n# pragma message(HUNTER_INFO(__GLIBCPP__))\n#endif\n\n#if defined(__GLIBCXX_BITSIZE_INT_N_0)\n# pragma message(HUNTER_INFO(__GLIBCXX_BITSIZE_INT_N_0))\n#endif\n\n#if defined(__GLIBCXX_TYPE_INT_N_0)\n# pragma message(HUNTER_INFO(__GLIBCXX_TYPE_INT_N_0))\n#endif\n\n#if defined(__GLIBCXX__)\n# pragma message(HUNTER_INFO(__GLIBCXX__))\n#endif\n\n#if defined(__GLIBC__)\n# pragma message(HUNTER_INFO(__GLIBC__))\n#endif\n\n#if defined(__GNUC_GNU_INLINE__)\n# pragma message(HUNTER_INFO(__GNUC_GNU_INLINE__))\n#endif\n\n#if defined(__GNUC_LIBSTD_MINOR__)\n# pragma message(HUNTER_INFO(__GNUC_LIBSTD_MINOR__))\n#endif\n\n#if defined(__GNUC_LIBSTD__)\n# pragma message(HUNTER_INFO(__GNUC_LIBSTD__))\n#endif\n\n#if defined(__GNUC_MINOR__)\n# pragma message(HUNTER_INFO(__GNUC_MINOR__))\n#endif\n\n#if defined(__GNUC_PATCHLEVEL__)\n# pragma message(HUNTER_INFO(__GNUC_PATCHLEVEL__))\n#endif\n\n#if defined(__GNUC_STDC_INLINE__)\n# pragma message(HUNTER_INFO(__GNUC_STDC_INLINE__))\n#endif\n\n#if defined(__GNUC__)\n# pragma message(HUNTER_INFO(__GNUC__))\n#endif\n\n#if defined(__GNUG__)\n# pragma message(HUNTER_INFO(__GNUG__))\n#endif\n\n#if defined(__GNU_LIBRARY__)\n# pragma message(HUNTER_INFO(__GNU_LIBRARY__))\n#endif\n\n#if defined(__GXX_ABI_VERSION)\n# pragma message(HUNTER_INFO(__GXX_ABI_VERSION))\n#endif\n\n#if defined(__GXX_EXPERIMENTAL_CXX0X__)\n# pragma message(HUNTER_INFO(__GXX_EXPERIMENTAL_CXX0X__))\n#endif\n\n#if defined(__GXX_RTTI)\n# pragma message(HUNTER_INFO(__GXX_RTTI))\n#endif\n\n#if defined(__GXX_TYPEINFO_EQUALITY_INLINE)\n# pragma message(HUNTER_INFO(__GXX_TYPEINFO_EQUALITY_INLINE))\n#endif\n\n#if defined(__GXX_WEAK__)\n# pragma message(HUNTER_INFO(__GXX_WEAK__))\n#endif\n\n#if defined(__HAIKU__)\n# pragma message(HUNTER_INFO(__HAIKU__))\n#endif\n\n#if defined(__HA_FBIT__)\n# pragma message(HUNTER_INFO(__HA_FBIT__))\n#endif\n\n#if defined(__HA_IBIT__)\n# pragma message(HUNTER_INFO(__HA_IBIT__))\n#endif\n\n#if defined(__HIGHC__)\n# pragma message(HUNTER_INFO(__HIGHC__))\n#endif\n\n#if defined(__HPPA11__)\n# pragma message(HUNTER_INFO(__HPPA11__))\n#endif\n\n#if defined(__HPPA20__)\n# pragma message(HUNTER_INFO(__HPPA20__))\n#endif\n\n#if defined(__HPPA__)\n# pragma message(HUNTER_INFO(__HPPA__))\n#endif\n\n#if defined(__HP_aCC)\n# pragma message(HUNTER_INFO(__HP_aCC))\n#endif\n\n#if defined(__HQ_FBIT__)\n# pragma message(HUNTER_INFO(__HQ_FBIT__))\n#endif\n\n#if defined(__HQ_IBIT__)\n# pragma message(HUNTER_INFO(__HQ_IBIT__))\n#endif\n\n#if defined(__I86__)\n# pragma message(HUNTER_INFO(__I86__))\n#endif\n\n#if defined(__IA64__)\n# pragma message(HUNTER_INFO(__IA64__))\n#endif\n\n#if defined(__IAR_SYSTEMS_ICC__)\n# pragma message(HUNTER_INFO(__IAR_SYSTEMS_ICC__))\n#endif\n\n#if defined(__IBMCPP__)\n# pragma message(HUNTER_INFO(__IBMCPP__))\n#endif\n\n#if defined(__ICC)\n# pragma message(HUNTER_INFO(__ICC))\n#endif\n\n#if defined(__ICL)\n# pragma message(HUNTER_INFO(__ICL))\n#endif\n\n#if defined(__INT16_C)\n# pragma message(HUNTER_INFO(__INT16_C))\n#endif\n\n#if defined(__INT16_MAX__)\n# pragma message(HUNTER_INFO(__INT16_MAX__))\n#endif\n\n#if defined(__INT16_TYPE__)\n# pragma message(HUNTER_INFO(__INT16_TYPE__))\n#endif\n\n#if defined(__INT32_C)\n# pragma message(HUNTER_INFO(__INT32_C))\n#endif\n\n#if defined(__INT32_MAX__)\n# pragma message(HUNTER_INFO(__INT32_MAX__))\n#endif\n\n#if defined(__INT32_TYPE__)\n# pragma message(HUNTER_INFO(__INT32_TYPE__))\n#endif\n\n#if defined(__INT64_C)\n# pragma message(HUNTER_INFO(__INT64_C))\n#endif\n\n#if defined(__INT64_C_SUFFIX__)\n# pragma message(HUNTER_INFO(__INT64_C_SUFFIX__))\n#endif\n\n#if defined(__INT64_MAX__)\n# pragma message(HUNTER_INFO(__INT64_MAX__))\n#endif\n\n#if defined(__INT64_TYPE__)\n# pragma message(HUNTER_INFO(__INT64_TYPE__))\n#endif\n\n#if defined(__INT8_C)\n# pragma message(HUNTER_INFO(__INT8_C))\n#endif\n\n#if defined(__INT8_MAX__)\n# pragma message(HUNTER_INFO(__INT8_MAX__))\n#endif\n\n#if defined(__INT8_TYPE__)\n# pragma message(HUNTER_INFO(__INT8_TYPE__))\n#endif\n\n#if defined(__INTEL_COMPILER)\n# pragma message(HUNTER_INFO(__INTEL_COMPILER))\n#endif\n\n#if defined(__INTEL__)\n# pragma message(HUNTER_INFO(__INTEL__))\n#endif\n\n#if defined(__INTMAX_C)\n# pragma message(HUNTER_INFO(__INTMAX_C))\n#endif\n\n#if defined(__INTMAX_MAX__)\n# pragma message(HUNTER_INFO(__INTMAX_MAX__))\n#endif\n\n#if defined(__INTMAX_TYPE__)\n# pragma message(HUNTER_INFO(__INTMAX_TYPE__))\n#endif\n\n#if defined(__INTMAX_WIDTH__)\n# pragma message(HUNTER_INFO(__INTMAX_WIDTH__))\n#endif\n\n#if defined(__INTPTR_MAX__)\n# pragma message(HUNTER_INFO(__INTPTR_MAX__))\n#endif\n\n#if defined(__INTPTR_TYPE__)\n# pragma message(HUNTER_INFO(__INTPTR_TYPE__))\n#endif\n\n#if defined(__INTPTR_WIDTH__)\n# pragma message(HUNTER_INFO(__INTPTR_WIDTH__))\n#endif\n\n#if defined(__INT_FAST16_MAX__)\n# pragma message(HUNTER_INFO(__INT_FAST16_MAX__))\n#endif\n\n#if defined(__INT_FAST16_TYPE__)\n# pragma message(HUNTER_INFO(__INT_FAST16_TYPE__))\n#endif\n\n#if defined(__INT_FAST32_MAX__)\n# pragma message(HUNTER_INFO(__INT_FAST32_MAX__))\n#endif\n\n#if defined(__INT_FAST32_TYPE__)\n# pragma message(HUNTER_INFO(__INT_FAST32_TYPE__))\n#endif\n\n#if defined(__INT_FAST64_MAX__)\n# pragma message(HUNTER_INFO(__INT_FAST64_MAX__))\n#endif\n\n#if defined(__INT_FAST64_TYPE__)\n# pragma message(HUNTER_INFO(__INT_FAST64_TYPE__))\n#endif\n\n#if defined(__INT_FAST8_MAX__)\n# pragma message(HUNTER_INFO(__INT_FAST8_MAX__))\n#endif\n\n#if defined(__INT_FAST8_TYPE__)\n# pragma message(HUNTER_INFO(__INT_FAST8_TYPE__))\n#endif\n\n#if defined(__INT_LEAST16_MAX__)\n# pragma message(HUNTER_INFO(__INT_LEAST16_MAX__))\n#endif\n\n#if defined(__INT_LEAST16_TYPE__)\n# pragma message(HUNTER_INFO(__INT_LEAST16_TYPE__))\n#endif\n\n#if defined(__INT_LEAST32_MAX__)\n# pragma message(HUNTER_INFO(__INT_LEAST32_MAX__))\n#endif\n\n#if defined(__INT_LEAST32_TYPE__)\n# pragma message(HUNTER_INFO(__INT_LEAST32_TYPE__))\n#endif\n\n#if defined(__INT_LEAST64_MAX__)\n# pragma message(HUNTER_INFO(__INT_LEAST64_MAX__))\n#endif\n\n#if defined(__INT_LEAST64_TYPE__)\n# pragma message(HUNTER_INFO(__INT_LEAST64_TYPE__))\n#endif\n\n#if defined(__INT_LEAST8_MAX__)\n# pragma message(HUNTER_INFO(__INT_LEAST8_MAX__))\n#endif\n\n#if defined(__INT_LEAST8_TYPE__)\n# pragma message(HUNTER_INFO(__INT_LEAST8_TYPE__))\n#endif\n\n#if defined(__INT_MAX__)\n# pragma message(HUNTER_INFO(__INT_MAX__))\n#endif\n\n#if defined(__KCC)\n# pragma message(HUNTER_INFO(__KCC))\n#endif\n\n#if defined(__LACCUM_EPSILON__)\n# pragma message(HUNTER_INFO(__LACCUM_EPSILON__))\n#endif\n\n#if defined(__LACCUM_FBIT__)\n# pragma message(HUNTER_INFO(__LACCUM_FBIT__))\n#endif\n\n#if defined(__LACCUM_IBIT__)\n# pragma message(HUNTER_INFO(__LACCUM_IBIT__))\n#endif\n\n#if defined(__LACCUM_MAX__)\n# pragma message(HUNTER_INFO(__LACCUM_MAX__))\n#endif\n\n#if defined(__LACCUM_MIN__)\n# pragma message(HUNTER_INFO(__LACCUM_MIN__))\n#endif\n\n#if defined(__LDBL_DENORM_MIN__)\n# pragma message(HUNTER_INFO(__LDBL_DENORM_MIN__))\n#endif\n\n#if defined(__LDBL_DIG__)\n# pragma message(HUNTER_INFO(__LDBL_DIG__))\n#endif\n\n#if defined(__LDBL_EPSILON__)\n# pragma message(HUNTER_INFO(__LDBL_EPSILON__))\n#endif\n\n#if defined(__LDBL_HAS_DENORM__)\n# pragma message(HUNTER_INFO(__LDBL_HAS_DENORM__))\n#endif\n\n#if defined(__LDBL_HAS_INFINITY__)\n# pragma message(HUNTER_INFO(__LDBL_HAS_INFINITY__))\n#endif\n\n#if defined(__LDBL_HAS_QUIET_NAN__)\n# pragma message(HUNTER_INFO(__LDBL_HAS_QUIET_NAN__))\n#endif\n\n#if defined(__LDBL_MANT_DIG__)\n# pragma message(HUNTER_INFO(__LDBL_MANT_DIG__))\n#endif\n\n#if defined(__LDBL_MAX_10_EXP__)\n# pragma message(HUNTER_INFO(__LDBL_MAX_10_EXP__))\n#endif\n\n#if defined(__LDBL_MAX_EXP__)\n# pragma message(HUNTER_INFO(__LDBL_MAX_EXP__))\n#endif\n\n#if defined(__LDBL_MAX__)\n# pragma message(HUNTER_INFO(__LDBL_MAX__))\n#endif\n\n#if defined(__LDBL_MIN_10_EXP__)\n# pragma message(HUNTER_INFO(__LDBL_MIN_10_EXP__))\n#endif\n\n#if defined(__LDBL_MIN_EXP__)\n# pragma message(HUNTER_INFO(__LDBL_MIN_EXP__))\n#endif\n\n#if defined(__LDBL_MIN__)\n# pragma message(HUNTER_INFO(__LDBL_MIN__))\n#endif\n\n#if defined(__LFRACT_EPSILON__)\n# pragma message(HUNTER_INFO(__LFRACT_EPSILON__))\n#endif\n\n#if defined(__LFRACT_FBIT__)\n# pragma message(HUNTER_INFO(__LFRACT_FBIT__))\n#endif\n\n#if defined(__LFRACT_IBIT__)\n# pragma message(HUNTER_INFO(__LFRACT_IBIT__))\n#endif\n\n#if defined(__LFRACT_MAX__)\n# pragma message(HUNTER_INFO(__LFRACT_MAX__))\n#endif\n\n#if defined(__LFRACT_MIN__)\n# pragma message(HUNTER_INFO(__LFRACT_MIN__))\n#endif\n\n#if defined(__LIBCOMO__)\n# pragma message(HUNTER_INFO(__LIBCOMO__))\n#endif\n\n#if defined(__LIBREL__)\n# pragma message(HUNTER_INFO(__LIBREL__))\n#endif\n\n#if defined(__LITTLE_ENDIAN)\n# pragma message(HUNTER_INFO(__LITTLE_ENDIAN))\n#endif\n\n#if defined(__LITTLE_ENDIAN__)\n# pragma message(HUNTER_INFO(__LITTLE_ENDIAN__))\n#endif\n\n#if defined(__LLACCUM_EPSILON__)\n# pragma message(HUNTER_INFO(__LLACCUM_EPSILON__))\n#endif\n\n#if defined(__LLACCUM_FBIT__)\n# pragma message(HUNTER_INFO(__LLACCUM_FBIT__))\n#endif\n\n#if defined(__LLACCUM_IBIT__)\n# pragma message(HUNTER_INFO(__LLACCUM_IBIT__))\n#endif\n\n#if defined(__LLACCUM_MAX__)\n# pragma message(HUNTER_INFO(__LLACCUM_MAX__))\n#endif\n\n#if defined(__LLACCUM_MIN__)\n# pragma message(HUNTER_INFO(__LLACCUM_MIN__))\n#endif\n\n#if defined(__LLFRACT_EPSILON__)\n# pragma message(HUNTER_INFO(__LLFRACT_EPSILON__))\n#endif\n\n#if defined(__LLFRACT_FBIT__)\n# pragma message(HUNTER_INFO(__LLFRACT_FBIT__))\n#endif\n\n#if defined(__LLFRACT_IBIT__)\n# pragma message(HUNTER_INFO(__LLFRACT_IBIT__))\n#endif\n\n#if defined(__LLFRACT_MAX__)\n# pragma message(HUNTER_INFO(__LLFRACT_MAX__))\n#endif\n\n#if defined(__LLFRACT_MIN__)\n# pragma message(HUNTER_INFO(__LLFRACT_MIN__))\n#endif\n\n#if defined(__LONG_LONG_MAX__)\n# pragma message(HUNTER_INFO(__LONG_LONG_MAX__))\n#endif\n\n#if defined(__LONG_MAX__)\n# pragma message(HUNTER_INFO(__LONG_MAX__))\n#endif\n\n#if defined(__LP64__)\n# pragma message(HUNTER_INFO(__LP64__))\n#endif\n\n#if defined(__MACH__)\n# pragma message(HUNTER_INFO(__MACH__))\n#endif\n\n#if defined(__MIC__)\n# pragma message(HUNTER_INFO(__MIC__))\n#endif\n\n#if defined(__MINGW32_VERSION_MAJOR)\n# pragma message(HUNTER_INFO(__MINGW32_VERSION_MAJOR))\n#endif\n\n#if defined(__MINGW32_VERSION_MINOR)\n# pragma message(HUNTER_INFO(__MINGW32_VERSION_MINOR))\n#endif\n\n#if defined(__MINGW32__)\n# pragma message(HUNTER_INFO(__MINGW32__))\n#endif\n\n#if defined(__MINGW64_VERSION_MAJOR)\n# pragma message(HUNTER_INFO(__MINGW64_VERSION_MAJOR))\n#endif\n\n#if defined(__MINGW64_VERSION_MINOR)\n# pragma message(HUNTER_INFO(__MINGW64_VERSION_MINOR))\n#endif\n\n#if defined(__MINGW64__)\n# pragma message(HUNTER_INFO(__MINGW64__))\n#endif\n\n#if defined(__MIPSEB)\n# pragma message(HUNTER_INFO(__MIPSEB))\n#endif\n\n#if defined(__MIPSEB__)\n# pragma message(HUNTER_INFO(__MIPSEB__))\n#endif\n\n#if defined(__MIPSEL)\n# pragma message(HUNTER_INFO(__MIPSEL))\n#endif\n\n#if defined(__MIPSEL__)\n# pragma message(HUNTER_INFO(__MIPSEL__))\n#endif\n\n#if defined(__MIPS_ISA2__)\n# pragma message(HUNTER_INFO(__MIPS_ISA2__))\n#endif\n\n#if defined(__MIPS_ISA3__)\n# pragma message(HUNTER_INFO(__MIPS_ISA3__))\n#endif\n\n#if defined(__MIPS_ISA4__)\n# pragma message(HUNTER_INFO(__MIPS_ISA4__))\n#endif\n\n#if defined(__MIPS__)\n# pragma message(HUNTER_INFO(__MIPS__))\n#endif\n\n#if defined(__MMX__)\n# pragma message(HUNTER_INFO(__MMX__))\n#endif\n\n#if defined(__MRC__)\n# pragma message(HUNTER_INFO(__MRC__))\n#endif\n\n#if defined(__MSIPL_COMPILE_H)\n# pragma message(HUNTER_INFO(__MSIPL_COMPILE_H))\n#endif\n\n#if defined(__MSL_CPP__)\n# pragma message(HUNTER_INFO(__MSL_CPP__))\n#endif\n\n#if defined(__MSL__)\n# pragma message(HUNTER_INFO(__MSL__))\n#endif\n\n#if defined(__MSVC_RUNTIME_CHECKS)\n# pragma message(HUNTER_INFO(__MSVC_RUNTIME_CHECKS))\n#endif\n\n#if defined(__MWERKS__)\n# pragma message(HUNTER_INFO(__MWERKS__))\n#endif\n\n#if defined(__NETBSD__)\n# pragma message(HUNTER_INFO(__NETBSD__))\n#endif\n\n#if defined(__NETBSD_version)\n# pragma message(HUNTER_INFO(__NETBSD_version))\n#endif\n\n#if defined(__NO_MATH_INLINES)\n# pragma message(HUNTER_INFO(__NO_MATH_INLINES))\n#endif\n\n#if defined(__NetBSD_Version)\n# pragma message(HUNTER_INFO(__NetBSD_Version))\n#endif\n\n#if defined(__NetBSD__)\n# pragma message(HUNTER_INFO(__NetBSD__))\n#endif\n\n#if defined(__OBJC__)\n# pragma message(HUNTER_INFO(__OBJC__))\n#endif\n\n#if defined(__ORDER_BIG_ENDIAN__)\n# pragma message(HUNTER_INFO(__ORDER_BIG_ENDIAN__))\n#endif\n\n#if defined(__ORDER_LITTLE_ENDIAN__)\n# pragma message(HUNTER_INFO(__ORDER_LITTLE_ENDIAN__))\n#endif\n\n#if defined(__ORDER_PDP_ENDIAN__)\n# pragma message(HUNTER_INFO(__ORDER_PDP_ENDIAN__))\n#endif\n\n#if defined(__OS400__)\n# pragma message(HUNTER_INFO(__OS400__))\n#endif\n\n#if defined(__OpenBSD__)\n# pragma message(HUNTER_INFO(__OpenBSD__))\n#endif\n\n#if defined(__PA7100__)\n# pragma message(HUNTER_INFO(__PA7100__))\n#endif\n\n#if defined(__PA8000__)\n# pragma message(HUNTER_INFO(__PA8000__))\n#endif\n\n#if defined(__PATHCC__)\n# pragma message(HUNTER_INFO(__PATHCC__))\n#endif\n\n#if defined(__PDP_ENDIAN)\n# pragma message(HUNTER_INFO(__PDP_ENDIAN))\n#endif\n\n#if defined(__PGI)\n# pragma message(HUNTER_INFO(__PGI))\n#endif\n\n#if defined(__PGIC_MINOR__)\n# pragma message(HUNTER_INFO(__PGIC_MINOR__))\n#endif\n\n#if defined(__PGIC_PATCHLEVEL__)\n# pragma message(HUNTER_INFO(__PGIC_PATCHLEVEL__))\n#endif\n\n#if defined(__PGIC__)\n# pragma message(HUNTER_INFO(__PGIC__))\n#endif\n\n#if defined(__PIC__)\n# pragma message(HUNTER_INFO(__PIC__))\n#endif\n\n#if defined(__PIE__)\n# pragma message(HUNTER_INFO(__PIE__))\n#endif\n\n#if defined(__POINTER_WIDTH__)\n# pragma message(HUNTER_INFO(__POINTER_WIDTH__))\n#endif\n\n#if defined(__POWERPC__)\n# pragma message(HUNTER_INFO(__POWERPC__))\n#endif\n\n#if defined(__PPCBROADWAY__)\n# pragma message(HUNTER_INFO(__PPCBROADWAY__))\n#endif\n\n#if defined(__PPCGECKO__)\n# pragma message(HUNTER_INFO(__PPCGECKO__))\n#endif\n\n#if defined(__PRAGMA_REDEFINE_EXTNAME)\n# pragma message(HUNTER_INFO(__PRAGMA_REDEFINE_EXTNAME))\n#endif\n\n#if defined(__PTRDIFF_MAX__)\n# pragma message(HUNTER_INFO(__PTRDIFF_MAX__))\n#endif\n\n#if defined(__PTRDIFF_TYPE__)\n# pragma message(HUNTER_INFO(__PTRDIFF_TYPE__))\n#endif\n\n#if defined(__PTRDIFF_WIDTH__)\n# pragma message(HUNTER_INFO(__PTRDIFF_WIDTH__))\n#endif\n\n#if defined(__QNXNTO__)\n# pragma message(HUNTER_INFO(__QNXNTO__))\n#endif\n\n#if defined(__QNX__)\n# pragma message(HUNTER_INFO(__QNX__))\n#endif\n\n#if defined(__QQ_FBIT__)\n# pragma message(HUNTER_INFO(__QQ_FBIT__))\n#endif\n\n#if defined(__QQ_IBIT__)\n# pragma message(HUNTER_INFO(__QQ_IBIT__))\n#endif\n\n#if defined(__REGISTER_PREFIX__)\n# pragma message(HUNTER_INFO(__REGISTER_PREFIX__))\n#endif\n\n#if defined(__RISC2_0__)\n# pragma message(HUNTER_INFO(__RISC2_0__))\n#endif\n\n#if defined(__SACCUM_EPSILON__)\n# pragma message(HUNTER_INFO(__SACCUM_EPSILON__))\n#endif\n\n#if defined(__SACCUM_FBIT__)\n# pragma message(HUNTER_INFO(__SACCUM_FBIT__))\n#endif\n\n#if defined(__SACCUM_IBIT__)\n# pragma message(HUNTER_INFO(__SACCUM_IBIT__))\n#endif\n\n#if defined(__SACCUM_MAX__)\n# pragma message(HUNTER_INFO(__SACCUM_MAX__))\n#endif\n\n#if defined(__SACCUM_MIN__)\n# pragma message(HUNTER_INFO(__SACCUM_MIN__))\n#endif\n\n#if defined(__SA_FBIT__)\n# pragma message(HUNTER_INFO(__SA_FBIT__))\n#endif\n\n#if defined(__SA_IBIT__)\n# pragma message(HUNTER_INFO(__SA_IBIT__))\n#endif\n\n#if defined(__SCHAR_MAX__)\n# pragma message(HUNTER_INFO(__SCHAR_MAX__))\n#endif\n\n#if defined(__SEG_FS)\n# pragma message(HUNTER_INFO(__SEG_FS))\n#endif\n\n#if defined(__SEG_GS)\n# pragma message(HUNTER_INFO(__SEG_GS))\n#endif\n\n#if defined(__SFRACT_EPSILON__)\n# pragma message(HUNTER_INFO(__SFRACT_EPSILON__))\n#endif\n\n#if defined(__SFRACT_FBIT__)\n# pragma message(HUNTER_INFO(__SFRACT_FBIT__))\n#endif\n\n#if defined(__SFRACT_IBIT__)\n# pragma message(HUNTER_INFO(__SFRACT_IBIT__))\n#endif\n\n#if defined(__SFRACT_MAX__)\n# pragma message(HUNTER_INFO(__SFRACT_MAX__))\n#endif\n\n#if defined(__SFRACT_MIN__)\n# pragma message(HUNTER_INFO(__SFRACT_MIN__))\n#endif\n\n#if defined(__SGI_STL)\n# pragma message(HUNTER_INFO(__SGI_STL))\n#endif\n\n#if defined(__SGI_STL_PORT)\n# pragma message(HUNTER_INFO(__SGI_STL_PORT))\n#endif\n\n#if defined(__SH3__)\n# pragma message(HUNTER_INFO(__SH3__))\n#endif\n\n#if defined(__SH4__)\n# pragma message(HUNTER_INFO(__SH4__))\n#endif\n\n#if defined(__SH5__)\n# pragma message(HUNTER_INFO(__SH5__))\n#endif\n\n#if defined(__SHRT_MAX__)\n# pragma message(HUNTER_INFO(__SHRT_MAX__))\n#endif\n\n#if defined(__SIG_ATOMIC_MAX__)\n# pragma message(HUNTER_INFO(__SIG_ATOMIC_MAX__))\n#endif\n\n#if defined(__SIG_ATOMIC_MIN__)\n# pragma message(HUNTER_INFO(__SIG_ATOMIC_MIN__))\n#endif\n\n#if defined(__SIG_ATOMIC_TYPE__)\n# pragma message(HUNTER_INFO(__SIG_ATOMIC_TYPE__))\n#endif\n\n#if defined(__SIG_ATOMIC_WIDTH__)\n# pragma message(HUNTER_INFO(__SIG_ATOMIC_WIDTH__))\n#endif\n\n#if defined(__SIZEOF_DOUBLE__)\n# pragma message(HUNTER_INFO(__SIZEOF_DOUBLE__))\n#endif\n\n#if defined(__SIZEOF_FLOAT128__)\n# pragma message(HUNTER_INFO(__SIZEOF_FLOAT128__))\n#endif\n\n#if defined(__SIZEOF_FLOAT80__)\n# pragma message(HUNTER_INFO(__SIZEOF_FLOAT80__))\n#endif\n\n#if defined(__SIZEOF_FLOAT__)\n# pragma message(HUNTER_INFO(__SIZEOF_FLOAT__))\n#endif\n\n#if defined(__SIZEOF_INT128__)\n# pragma message(HUNTER_INFO(__SIZEOF_INT128__))\n#endif\n\n#if defined(__SIZEOF_INT__)\n# pragma message(HUNTER_INFO(__SIZEOF_INT__))\n#endif\n\n#if defined(__SIZEOF_LONG_DOUBLE__)\n# pragma message(HUNTER_INFO(__SIZEOF_LONG_DOUBLE__))\n#endif\n\n#if defined(__SIZEOF_LONG_LONG__)\n# pragma message(HUNTER_INFO(__SIZEOF_LONG_LONG__))\n#endif\n\n#if defined(__SIZEOF_LONG__)\n# pragma message(HUNTER_INFO(__SIZEOF_LONG__))\n#endif\n\n#if defined(__SIZEOF_POINTER__)\n# pragma message(HUNTER_INFO(__SIZEOF_POINTER__))\n#endif\n\n#if defined(__SIZEOF_PTRDIFF_T__)\n# pragma message(HUNTER_INFO(__SIZEOF_PTRDIFF_T__))\n#endif\n\n#if defined(__SIZEOF_SHORT__)\n# pragma message(HUNTER_INFO(__SIZEOF_SHORT__))\n#endif\n\n#if defined(__SIZEOF_SIZE_T__)\n# pragma message(HUNTER_INFO(__SIZEOF_SIZE_T__))\n#endif\n\n#if defined(__SIZEOF_WCHAR_T__)\n# pragma message(HUNTER_INFO(__SIZEOF_WCHAR_T__))\n#endif\n\n#if defined(__SIZEOF_WINT_T__)\n# pragma message(HUNTER_INFO(__SIZEOF_WINT_T__))\n#endif\n\n#if defined(__SIZE_MAX__)\n# pragma message(HUNTER_INFO(__SIZE_MAX__))\n#endif\n\n#if defined(__SIZE_TYPE__)\n# pragma message(HUNTER_INFO(__SIZE_TYPE__))\n#endif\n\n#if defined(__SIZE_WIDTH__)\n# pragma message(HUNTER_INFO(__SIZE_WIDTH__))\n#endif\n\n#if defined(__SQ_FBIT__)\n# pragma message(HUNTER_INFO(__SQ_FBIT__))\n#endif\n\n#if defined(__SQ_IBIT__)\n# pragma message(HUNTER_INFO(__SQ_IBIT__))\n#endif\n\n#if defined(__SSE2_MATH__)\n# pragma message(HUNTER_INFO(__SSE2_MATH__))\n#endif\n\n#if defined(__SSE2__)\n# pragma message(HUNTER_INFO(__SSE2__))\n#endif\n\n#if defined(__SSE3__)\n# pragma message(HUNTER_INFO(__SSE3__))\n#endif\n\n#if defined(__SSE4A__)\n# pragma message(HUNTER_INFO(__SSE4A__))\n#endif\n\n#if defined(__SSE4_1__)\n# pragma message(HUNTER_INFO(__SSE4_1__))\n#endif\n\n#if defined(__SSE4_2__)\n# pragma message(HUNTER_INFO(__SSE4_2__))\n#endif\n\n#if defined(__SSE_MATH__)\n# pragma message(HUNTER_INFO(__SSE_MATH__))\n#endif\n\n#if defined(__SSE__)\n# pragma message(HUNTER_INFO(__SSE__))\n#endif\n\n#if defined(__SSP_STRONG__)\n# pragma message(HUNTER_INFO(__SSP_STRONG__))\n#endif\n\n#if defined(__SSP__)\n# pragma message(HUNTER_INFO(__SSP__))\n#endif\n\n#if defined(__SSSE3__)\n# pragma message(HUNTER_INFO(__SSSE3__))\n#endif\n\n#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)\n# pragma message(HUNTER_INFO(__STDCPP_DEFAULT_NEW_ALIGNMENT__))\n#endif\n\n#if defined(__STDCPP_STRICT_POINTER_SAFETY__)\n# pragma message(HUNTER_INFO(__STDCPP_STRICT_POINTER_SAFETY__))\n#endif\n\n#if defined(__STDCPP_THREADS__)\n# pragma message(HUNTER_INFO(__STDCPP_THREADS__))\n#endif\n\n#if defined(__STDC_HOSTED__)\n# pragma message(HUNTER_INFO(__STDC_HOSTED__))\n#endif\n\n#if defined(__STDC_IEC_559_COMPLEX__)\n# pragma message(HUNTER_INFO(__STDC_IEC_559_COMPLEX__))\n#endif\n\n#if defined(__STDC_IEC_559__)\n# pragma message(HUNTER_INFO(__STDC_IEC_559__))\n#endif\n\n#if defined(__STDC_ISO_10646__)\n# pragma message(HUNTER_INFO(__STDC_ISO_10646__))\n#endif\n\n#if defined(__STDC_MB_MIGHT_NEQ_WC__)\n# pragma message(HUNTER_INFO(__STDC_MB_MIGHT_NEQ_WC__))\n#endif\n\n#if defined(__STDC_NO_THREADS__)\n# pragma message(HUNTER_INFO(__STDC_NO_THREADS__))\n#endif\n\n#if defined(__STDC_UTF_16__)\n# pragma message(HUNTER_INFO(__STDC_UTF_16__))\n#endif\n\n#if defined(__STDC_UTF_32__)\n# pragma message(HUNTER_INFO(__STDC_UTF_32__))\n#endif\n\n#if defined(__STDC_VERSION__)\n# pragma message(HUNTER_INFO(__STDC_VERSION__))\n#endif\n\n#if defined(__STDC__)\n# pragma message(HUNTER_INFO(__STDC__))\n#endif\n\n#if defined(__STD_RWCOMPILER_H__)\n# pragma message(HUNTER_INFO(__STD_RWCOMPILER_H__))\n#endif\n\n#if defined(__STL_CONFIG_H)\n# pragma message(HUNTER_INFO(__STL_CONFIG_H))\n#endif\n\n#if defined(__SUNPRO_C)\n# pragma message(HUNTER_INFO(__SUNPRO_C))\n#endif\n\n#if defined(__SUNPRO_CC)\n# pragma message(HUNTER_INFO(__SUNPRO_CC))\n#endif\n\n#if defined(__SVR4)\n# pragma message(HUNTER_INFO(__SVR4))\n#endif\n\n#if defined(__SYSC_ZARCH__)\n# pragma message(HUNTER_INFO(__SYSC_ZARCH__))\n#endif\n\n#if defined(__SYSC__)\n# pragma message(HUNTER_INFO(__SYSC__))\n#endif\n\n#if defined(__TARGET_ARCH_ARM)\n# pragma message(HUNTER_INFO(__TARGET_ARCH_ARM))\n#endif\n\n#if defined(__TARGET_ARCH_THUMB)\n# pragma message(HUNTER_INFO(__TARGET_ARCH_THUMB))\n#endif\n\n#if defined(__TARGET_LIB__)\n# pragma message(HUNTER_INFO(__TARGET_LIB__))\n#endif\n\n#if defined(__TA_FBIT__)\n# pragma message(HUNTER_INFO(__TA_FBIT__))\n#endif\n\n#if defined(__TA_IBIT__)\n# pragma message(HUNTER_INFO(__TA_IBIT__))\n#endif\n\n#if defined(__THUMBEB__)\n# pragma message(HUNTER_INFO(__THUMBEB__))\n#endif\n\n#if defined(__THUMBEL__)\n# pragma message(HUNTER_INFO(__THUMBEL__))\n#endif\n\n#if defined(__THUMB_INTERWORK__)\n# pragma message(HUNTER_INFO(__THUMB_INTERWORK__))\n#endif\n\n#if defined(__THW_370__)\n# pragma message(HUNTER_INFO(__THW_370__))\n#endif\n\n#if defined(__THW_INTEL__)\n# pragma message(HUNTER_INFO(__THW_INTEL__))\n#endif\n\n#if defined(__THW_RS6000)\n# pragma message(HUNTER_INFO(__THW_RS6000))\n#endif\n\n#if defined(__TOS_AIX__)\n# pragma message(HUNTER_INFO(__TOS_AIX__))\n#endif\n\n#if defined(__TOS_WIN__)\n# pragma message(HUNTER_INFO(__TOS_WIN__))\n#endif\n\n#if defined(__TQ_FBIT__)\n# pragma message(HUNTER_INFO(__TQ_FBIT__))\n#endif\n\n#if defined(__TQ_IBIT__)\n# pragma message(HUNTER_INFO(__TQ_IBIT__))\n#endif\n\n#if defined(__TenDRA__)\n# pragma message(HUNTER_INFO(__TenDRA__))\n#endif\n\n#if defined(__UACCUM_EPSILON__)\n# pragma message(HUNTER_INFO(__UACCUM_EPSILON__))\n#endif\n\n#if defined(__UACCUM_FBIT__)\n# pragma message(HUNTER_INFO(__UACCUM_FBIT__))\n#endif\n\n#if defined(__UACCUM_IBIT__)\n# pragma message(HUNTER_INFO(__UACCUM_IBIT__))\n#endif\n\n#if defined(__UACCUM_MAX__)\n# pragma message(HUNTER_INFO(__UACCUM_MAX__))\n#endif\n\n#if defined(__UACCUM_MIN__)\n# pragma message(HUNTER_INFO(__UACCUM_MIN__))\n#endif\n\n#if defined(__UCLIBC__)\n# pragma message(HUNTER_INFO(__UCLIBC__))\n#endif\n\n#if defined(__UDA_FBIT__)\n# pragma message(HUNTER_INFO(__UDA_FBIT__))\n#endif\n\n#if defined(__UDA_IBIT__)\n# pragma message(HUNTER_INFO(__UDA_IBIT__))\n#endif\n\n#if defined(__UDQ_FBIT__)\n# pragma message(HUNTER_INFO(__UDQ_FBIT__))\n#endif\n\n#if defined(__UDQ_IBIT__)\n# pragma message(HUNTER_INFO(__UDQ_IBIT__))\n#endif\n\n#if defined(__UFRACT_EPSILON__)\n# pragma message(HUNTER_INFO(__UFRACT_EPSILON__))\n#endif\n\n#if defined(__UFRACT_FBIT__)\n# pragma message(HUNTER_INFO(__UFRACT_FBIT__))\n#endif\n\n#if defined(__UFRACT_IBIT__)\n# pragma message(HUNTER_INFO(__UFRACT_IBIT__))\n#endif\n\n#if defined(__UFRACT_MAX__)\n# pragma message(HUNTER_INFO(__UFRACT_MAX__))\n#endif\n\n#if defined(__UFRACT_MIN__)\n# pragma message(HUNTER_INFO(__UFRACT_MIN__))\n#endif\n\n#if defined(__UHA_FBIT__)\n# pragma message(HUNTER_INFO(__UHA_FBIT__))\n#endif\n\n#if defined(__UHA_IBIT__)\n# pragma message(HUNTER_INFO(__UHA_IBIT__))\n#endif\n\n#if defined(__UHQ_FBIT__)\n# pragma message(HUNTER_INFO(__UHQ_FBIT__))\n#endif\n\n#if defined(__UHQ_IBIT__)\n# pragma message(HUNTER_INFO(__UHQ_IBIT__))\n#endif\n\n#if defined(__UINT16_C)\n# pragma message(HUNTER_INFO(__UINT16_C))\n#endif\n\n#if defined(__UINT16_MAX__)\n# pragma message(HUNTER_INFO(__UINT16_MAX__))\n#endif\n\n#if defined(__UINT16_TYPE__)\n# pragma message(HUNTER_INFO(__UINT16_TYPE__))\n#endif\n\n#if defined(__UINT32_C)\n# pragma message(HUNTER_INFO(__UINT32_C))\n#endif\n\n#if defined(__UINT32_MAX__)\n# pragma message(HUNTER_INFO(__UINT32_MAX__))\n#endif\n\n#if defined(__UINT32_TYPE__)\n# pragma message(HUNTER_INFO(__UINT32_TYPE__))\n#endif\n\n#if defined(__UINT64_C)\n# pragma message(HUNTER_INFO(__UINT64_C))\n#endif\n\n#if defined(__UINT64_MAX__)\n# pragma message(HUNTER_INFO(__UINT64_MAX__))\n#endif\n\n#if defined(__UINT64_TYPE__)\n# pragma message(HUNTER_INFO(__UINT64_TYPE__))\n#endif\n\n#if defined(__UINT8_C)\n# pragma message(HUNTER_INFO(__UINT8_C))\n#endif\n\n#if defined(__UINT8_MAX__)\n# pragma message(HUNTER_INFO(__UINT8_MAX__))\n#endif\n\n#if defined(__UINT8_TYPE__)\n# pragma message(HUNTER_INFO(__UINT8_TYPE__))\n#endif\n\n#if defined(__UINTMAX_C)\n# pragma message(HUNTER_INFO(__UINTMAX_C))\n#endif\n\n#if defined(__UINTMAX_MAX__)\n# pragma message(HUNTER_INFO(__UINTMAX_MAX__))\n#endif\n\n#if defined(__UINTMAX_TYPE__)\n# pragma message(HUNTER_INFO(__UINTMAX_TYPE__))\n#endif\n\n#if defined(__UINTPTR_MAX__)\n# pragma message(HUNTER_INFO(__UINTPTR_MAX__))\n#endif\n\n#if defined(__UINTPTR_TYPE__)\n# pragma message(HUNTER_INFO(__UINTPTR_TYPE__))\n#endif\n\n#if defined(__UINT_FAST16_MAX__)\n# pragma message(HUNTER_INFO(__UINT_FAST16_MAX__))\n#endif\n\n#if defined(__UINT_FAST16_TYPE__)\n# pragma message(HUNTER_INFO(__UINT_FAST16_TYPE__))\n#endif\n\n#if defined(__UINT_FAST32_MAX__)\n# pragma message(HUNTER_INFO(__UINT_FAST32_MAX__))\n#endif\n\n#if defined(__UINT_FAST32_TYPE__)\n# pragma message(HUNTER_INFO(__UINT_FAST32_TYPE__))\n#endif\n\n#if defined(__UINT_FAST64_MAX__)\n# pragma message(HUNTER_INFO(__UINT_FAST64_MAX__))\n#endif\n\n#if defined(__UINT_FAST64_TYPE__)\n# pragma message(HUNTER_INFO(__UINT_FAST64_TYPE__))\n#endif\n\n#if defined(__UINT_FAST8_MAX__)\n# pragma message(HUNTER_INFO(__UINT_FAST8_MAX__))\n#endif\n\n#if defined(__UINT_FAST8_TYPE__)\n# pragma message(HUNTER_INFO(__UINT_FAST8_TYPE__))\n#endif\n\n#if defined(__UINT_LEAST16_MAX__)\n# pragma message(HUNTER_INFO(__UINT_LEAST16_MAX__))\n#endif\n\n#if defined(__UINT_LEAST16_TYPE__)\n# pragma message(HUNTER_INFO(__UINT_LEAST16_TYPE__))\n#endif\n\n#if defined(__UINT_LEAST32_MAX__)\n# pragma message(HUNTER_INFO(__UINT_LEAST32_MAX__))\n#endif\n\n#if defined(__UINT_LEAST32_TYPE__)\n# pragma message(HUNTER_INFO(__UINT_LEAST32_TYPE__))\n#endif\n\n#if defined(__UINT_LEAST64_MAX__)\n# pragma message(HUNTER_INFO(__UINT_LEAST64_MAX__))\n#endif\n\n#if defined(__UINT_LEAST64_TYPE__)\n# pragma message(HUNTER_INFO(__UINT_LEAST64_TYPE__))\n#endif\n\n#if defined(__UINT_LEAST8_MAX__)\n# pragma message(HUNTER_INFO(__UINT_LEAST8_MAX__))\n#endif\n\n#if defined(__UINT_LEAST8_TYPE__)\n# pragma message(HUNTER_INFO(__UINT_LEAST8_TYPE__))\n#endif\n\n#if defined(__ULACCUM_EPSILON__)\n# pragma message(HUNTER_INFO(__ULACCUM_EPSILON__))\n#endif\n\n#if defined(__ULACCUM_FBIT__)\n# pragma message(HUNTER_INFO(__ULACCUM_FBIT__))\n#endif\n\n#if defined(__ULACCUM_IBIT__)\n# pragma message(HUNTER_INFO(__ULACCUM_IBIT__))\n#endif\n\n#if defined(__ULACCUM_MAX__)\n# pragma message(HUNTER_INFO(__ULACCUM_MAX__))\n#endif\n\n#if defined(__ULACCUM_MIN__)\n# pragma message(HUNTER_INFO(__ULACCUM_MIN__))\n#endif\n\n#if defined(__ULFRACT_EPSILON__)\n# pragma message(HUNTER_INFO(__ULFRACT_EPSILON__))\n#endif\n\n#if defined(__ULFRACT_FBIT__)\n# pragma message(HUNTER_INFO(__ULFRACT_FBIT__))\n#endif\n\n#if defined(__ULFRACT_IBIT__)\n# pragma message(HUNTER_INFO(__ULFRACT_IBIT__))\n#endif\n\n#if defined(__ULFRACT_MAX__)\n# pragma message(HUNTER_INFO(__ULFRACT_MAX__))\n#endif\n\n#if defined(__ULFRACT_MIN__)\n# pragma message(HUNTER_INFO(__ULFRACT_MIN__))\n#endif\n\n#if defined(__ULLACCUM_EPSILON__)\n# pragma message(HUNTER_INFO(__ULLACCUM_EPSILON__))\n#endif\n\n#if defined(__ULLACCUM_FBIT__)\n# pragma message(HUNTER_INFO(__ULLACCUM_FBIT__))\n#endif\n\n#if defined(__ULLACCUM_IBIT__)\n# pragma message(HUNTER_INFO(__ULLACCUM_IBIT__))\n#endif\n\n#if defined(__ULLACCUM_MAX__)\n# pragma message(HUNTER_INFO(__ULLACCUM_MAX__))\n#endif\n\n#if defined(__ULLACCUM_MIN__)\n# pragma message(HUNTER_INFO(__ULLACCUM_MIN__))\n#endif\n\n#if defined(__ULLFRACT_EPSILON__)\n# pragma message(HUNTER_INFO(__ULLFRACT_EPSILON__))\n#endif\n\n#if defined(__ULLFRACT_FBIT__)\n# pragma message(HUNTER_INFO(__ULLFRACT_FBIT__))\n#endif\n\n#if defined(__ULLFRACT_IBIT__)\n# pragma message(HUNTER_INFO(__ULLFRACT_IBIT__))\n#endif\n\n#if defined(__ULLFRACT_MAX__)\n# pragma message(HUNTER_INFO(__ULLFRACT_MAX__))\n#endif\n\n#if defined(__ULLFRACT_MIN__)\n# pragma message(HUNTER_INFO(__ULLFRACT_MIN__))\n#endif\n\n#if defined(__UQQ_FBIT__)\n# pragma message(HUNTER_INFO(__UQQ_FBIT__))\n#endif\n\n#if defined(__UQQ_IBIT__)\n# pragma message(HUNTER_INFO(__UQQ_IBIT__))\n#endif\n\n#if defined(__USACCUM_EPSILON__)\n# pragma message(HUNTER_INFO(__USACCUM_EPSILON__))\n#endif\n\n#if defined(__USACCUM_FBIT__)\n# pragma message(HUNTER_INFO(__USACCUM_FBIT__))\n#endif\n\n#if defined(__USACCUM_IBIT__)\n# pragma message(HUNTER_INFO(__USACCUM_IBIT__))\n#endif\n\n#if defined(__USACCUM_MAX__)\n# pragma message(HUNTER_INFO(__USACCUM_MAX__))\n#endif\n\n#if defined(__USACCUM_MIN__)\n# pragma message(HUNTER_INFO(__USACCUM_MIN__))\n#endif\n\n#if defined(__USA_FBIT__)\n# pragma message(HUNTER_INFO(__USA_FBIT__))\n#endif\n\n#if defined(__USA_IBIT__)\n# pragma message(HUNTER_INFO(__USA_IBIT__))\n#endif\n\n#if defined(__USER_LABEL_PREFIX__)\n# pragma message(HUNTER_INFO(__USER_LABEL_PREFIX__))\n#endif\n\n#if defined(__USFRACT_EPSILON__)\n# pragma message(HUNTER_INFO(__USFRACT_EPSILON__))\n#endif\n\n#if defined(__USFRACT_FBIT__)\n# pragma message(HUNTER_INFO(__USFRACT_FBIT__))\n#endif\n\n#if defined(__USFRACT_IBIT__)\n# pragma message(HUNTER_INFO(__USFRACT_IBIT__))\n#endif\n\n#if defined(__USFRACT_MAX__)\n# pragma message(HUNTER_INFO(__USFRACT_MAX__))\n#endif\n\n#if defined(__USFRACT_MIN__)\n# pragma message(HUNTER_INFO(__USFRACT_MIN__))\n#endif\n\n#if defined(__USING_SJLJ_EXCEPTIONS__)\n# pragma message(HUNTER_INFO(__USING_SJLJ_EXCEPTIONS__))\n#endif\n\n#if defined(__USQ_FBIT__)\n# pragma message(HUNTER_INFO(__USQ_FBIT__))\n#endif\n\n#if defined(__USQ_IBIT__)\n# pragma message(HUNTER_INFO(__USQ_IBIT__))\n#endif\n\n#if defined(__UTA_FBIT__)\n# pragma message(HUNTER_INFO(__UTA_FBIT__))\n#endif\n\n#if defined(__UTA_IBIT__)\n# pragma message(HUNTER_INFO(__UTA_IBIT__))\n#endif\n\n#if defined(__UTQ_FBIT__)\n# pragma message(HUNTER_INFO(__UTQ_FBIT__))\n#endif\n\n#if defined(__UTQ_IBIT__)\n# pragma message(HUNTER_INFO(__UTQ_IBIT__))\n#endif\n\n#if defined(__VECTOR4DOUBLE__)\n# pragma message(HUNTER_INFO(__VECTOR4DOUBLE__))\n#endif\n\n#if defined(__VEC__)\n# pragma message(HUNTER_INFO(__VEC__))\n#endif\n\n#if defined(__VERSION__)\n# pragma message(HUNTER_INFO(__VERSION__))\n#endif\n\n#if defined(__VFP_FP__)\n# pragma message(HUNTER_INFO(__VFP_FP__))\n#endif\n\n#if defined(__VMS)\n# pragma message(HUNTER_INFO(__VMS))\n#endif\n\n#if defined(__VMS_VER)\n# pragma message(HUNTER_INFO(__VMS_VER))\n#endif\n\n#if defined(__VSX__)\n# pragma message(HUNTER_INFO(__VSX__))\n#endif\n\n#if defined(__WATCOMC__)\n# pragma message(HUNTER_INFO(__WATCOMC__))\n#endif\n\n#if defined(__WCHAR_MAX__)\n# pragma message(HUNTER_INFO(__WCHAR_MAX__))\n#endif\n\n#if defined(__WCHAR_MIN__)\n# pragma message(HUNTER_INFO(__WCHAR_MIN__))\n#endif\n\n#if defined(__WCHAR_TYPE__)\n# pragma message(HUNTER_INFO(__WCHAR_TYPE__))\n#endif\n\n#if defined(__WCHAR_UNSIGNED__)\n# pragma message(HUNTER_INFO(__WCHAR_UNSIGNED__))\n#endif\n\n#if defined(__WCHAR_WIDTH__)\n# pragma message(HUNTER_INFO(__WCHAR_WIDTH__))\n#endif\n\n#if defined(__WIN32__)\n# pragma message(HUNTER_INFO(__WIN32__))\n#endif\n\n#if defined(__WINDOWS__)\n# pragma message(HUNTER_INFO(__WINDOWS__))\n#endif\n\n#if defined(__WINT_MAX__)\n# pragma message(HUNTER_INFO(__WINT_MAX__))\n#endif\n\n#if defined(__WINT_MIN__)\n# pragma message(HUNTER_INFO(__WINT_MIN__))\n#endif\n\n#if defined(__WINT_TYPE__)\n# pragma message(HUNTER_INFO(__WINT_TYPE__))\n#endif\n\n#if defined(__WINT_WIDTH__)\n# pragma message(HUNTER_INFO(__WINT_WIDTH__))\n#endif\n\n#if defined(__XOP__)\n# pragma message(HUNTER_INFO(__XOP__))\n#endif\n\n#if defined(__aarch64__)\n# pragma message(HUNTER_INFO(__aarch64__))\n#endif\n\n#if defined(__alpha)\n# pragma message(HUNTER_INFO(__alpha))\n#endif\n\n#if defined(__alpha__)\n# pragma message(HUNTER_INFO(__alpha__))\n#endif\n\n#if defined(__alpha_ev4__)\n# pragma message(HUNTER_INFO(__alpha_ev4__))\n#endif\n\n#if defined(__alpha_ev5__)\n# pragma message(HUNTER_INFO(__alpha_ev5__))\n#endif\n\n#if defined(__alpha_ev6__)\n# pragma message(HUNTER_INFO(__alpha_ev6__))\n#endif\n\n#if defined(__amd64)\n# pragma message(HUNTER_INFO(__amd64))\n#endif\n\n#if defined(__amd64__)\n# pragma message(HUNTER_INFO(__amd64__))\n#endif\n\n#if defined(__amigaos__)\n# pragma message(HUNTER_INFO(__amigaos__))\n#endif\n\n#if defined(__apple_build_version__)\n# pragma message(HUNTER_INFO(__apple_build_version__))\n#endif\n\n#if defined(__arm)\n# pragma message(HUNTER_INFO(__arm))\n#endif\n\n#if defined(__arm64)\n# pragma message(HUNTER_INFO(__arm64))\n#endif\n\n#if defined(__arm64__)\n# pragma message(HUNTER_INFO(__arm64__))\n#endif\n\n#if defined(__arm__)\n# pragma message(HUNTER_INFO(__arm__))\n#endif\n\n#if defined(__bfin__)\n# pragma message(HUNTER_INFO(__bfin__))\n#endif\n\n#if defined(__block)\n# pragma message(HUNTER_INFO(__block))\n#endif\n\n#if defined(__bsdi__)\n# pragma message(HUNTER_INFO(__bsdi__))\n#endif\n\n#if defined(__clang__)\n# pragma message(HUNTER_INFO(__clang__))\n#endif\n\n#if defined(__clang_major__)\n# pragma message(HUNTER_INFO(__clang_major__))\n#endif\n\n#if defined(__clang_minor__)\n# pragma message(HUNTER_INFO(__clang_minor__))\n#endif\n\n#if defined(__clang_patchlevel__)\n# pragma message(HUNTER_INFO(__clang_patchlevel__))\n#endif\n\n#if defined(__clang_version__)\n# pragma message(HUNTER_INFO(__clang_version__))\n#endif\n\n#if defined(__code_model_small__)\n# pragma message(HUNTER_INFO(__code_model_small__))\n#endif\n\n#if defined(__convex__)\n# pragma message(HUNTER_INFO(__convex__))\n#endif\n\n#if defined(__convex_c1__)\n# pragma message(HUNTER_INFO(__convex_c1__))\n#endif\n\n#if defined(__convex_c2__)\n# pragma message(HUNTER_INFO(__convex_c2__))\n#endif\n\n#if defined(__convex_c32__)\n# pragma message(HUNTER_INFO(__convex_c32__))\n#endif\n\n#if defined(__convex_c34__)\n# pragma message(HUNTER_INFO(__convex_c34__))\n#endif\n\n#if defined(__convex_c38__)\n# pragma message(HUNTER_INFO(__convex_c38__))\n#endif\n\n#if defined(__core2)\n# pragma message(HUNTER_INFO(__core2))\n#endif\n\n#if defined(__core2__)\n# pragma message(HUNTER_INFO(__core2__))\n#endif\n\n#if defined(__cplusplus)\n# pragma message(HUNTER_INFO(__cplusplus))\n#endif\n\n#if defined(__cplusplus_cli)\n# pragma message(HUNTER_INFO(__cplusplus_cli))\n#endif\n\n#if defined(__cplusplus_winrt)\n# pragma message(HUNTER_INFO(__cplusplus_winrt))\n#endif\n\n#if defined(__cpp_aggregate_nsdmi)\n# pragma message(HUNTER_INFO(__cpp_aggregate_nsdmi))\n#endif\n\n#if defined(__cpp_alias_templates)\n# pragma message(HUNTER_INFO(__cpp_alias_templates))\n#endif\n\n#if defined(__cpp_attributes)\n# pragma message(HUNTER_INFO(__cpp_attributes))\n#endif\n\n#if defined(__cpp_binary_literals)\n# pragma message(HUNTER_INFO(__cpp_binary_literals))\n#endif\n\n#if defined(__cpp_constexpr)\n# pragma message(HUNTER_INFO(__cpp_constexpr))\n#endif\n\n#if defined(__cpp_decltype)\n# pragma message(HUNTER_INFO(__cpp_decltype))\n#endif\n\n#if defined(__cpp_decltype_auto)\n# pragma message(HUNTER_INFO(__cpp_decltype_auto))\n#endif\n\n#if defined(__cpp_delegating_constructors)\n# pragma message(HUNTER_INFO(__cpp_delegating_constructors))\n#endif\n\n#if defined(__cpp_digit_separators)\n# pragma message(HUNTER_INFO(__cpp_digit_separators))\n#endif\n\n#if defined(__cpp_exceptions)\n# pragma message(HUNTER_INFO(__cpp_exceptions))\n#endif\n\n#if defined(__cpp_generic_lambdas)\n# pragma message(HUNTER_INFO(__cpp_generic_lambdas))\n#endif\n\n#if defined(__cpp_hex_float)\n# pragma message(HUNTER_INFO(__cpp_hex_float))\n#endif\n\n#if defined(__cpp_inheriting_constructors)\n# pragma message(HUNTER_INFO(__cpp_inheriting_constructors))\n#endif\n\n#if defined(__cpp_init_captures)\n# pragma message(HUNTER_INFO(__cpp_init_captures))\n#endif\n\n#if defined(__cpp_initializer_lists)\n# pragma message(HUNTER_INFO(__cpp_initializer_lists))\n#endif\n\n#if defined(__cpp_lambdas)\n# pragma message(HUNTER_INFO(__cpp_lambdas))\n#endif\n\n#if defined(__cpp_nsdmi)\n# pragma message(HUNTER_INFO(__cpp_nsdmi))\n#endif\n\n#if defined(__cpp_range_based_for)\n# pragma message(HUNTER_INFO(__cpp_range_based_for))\n#endif\n\n#if defined(__cpp_raw_strings)\n# pragma message(HUNTER_INFO(__cpp_raw_strings))\n#endif\n\n#if defined(__cpp_ref_qualifiers)\n# pragma message(HUNTER_INFO(__cpp_ref_qualifiers))\n#endif\n\n#if defined(__cpp_return_type_deduction)\n# pragma message(HUNTER_INFO(__cpp_return_type_deduction))\n#endif\n\n#if defined(__cpp_rtti)\n# pragma message(HUNTER_INFO(__cpp_rtti))\n#endif\n\n#if defined(__cpp_runtime_arrays)\n# pragma message(HUNTER_INFO(__cpp_runtime_arrays))\n#endif\n\n#if defined(__cpp_rvalue_reference)\n# pragma message(HUNTER_INFO(__cpp_rvalue_reference))\n#endif\n\n#if defined(__cpp_sized_deallocation)\n# pragma message(HUNTER_INFO(__cpp_sized_deallocation))\n#endif\n\n#if defined(__cpp_static_assert)\n# pragma message(HUNTER_INFO(__cpp_static_assert))\n#endif\n\n#if defined(__cpp_unicode_characters)\n# pragma message(HUNTER_INFO(__cpp_unicode_characters))\n#endif\n\n#if defined(__cpp_unicode_literals)\n# pragma message(HUNTER_INFO(__cpp_unicode_literals))\n#endif\n\n#if defined(__cpp_user_defined_literals)\n# pragma message(HUNTER_INFO(__cpp_user_defined_literals))\n#endif\n\n#if defined(__cpp_variable_templates)\n# pragma message(HUNTER_INFO(__cpp_variable_templates))\n#endif\n\n#if defined(__cpp_variadic_templates)\n# pragma message(HUNTER_INFO(__cpp_variadic_templates))\n#endif\n\n#if defined(__embedded_cplusplus)\n# pragma message(HUNTER_INFO(__embedded_cplusplus))\n#endif\n\n#if defined(__ghs)\n# pragma message(HUNTER_INFO(__ghs))\n#endif\n\n#if defined(__ghs__)\n# pragma message(HUNTER_INFO(__ghs__))\n#endif\n\n#if defined(__gnu_linux__)\n# pragma message(HUNTER_INFO(__gnu_linux__))\n#endif\n\n#if defined(__hppa)\n# pragma message(HUNTER_INFO(__hppa))\n#endif\n\n#if defined(__hppa__)\n# pragma message(HUNTER_INFO(__hppa__))\n#endif\n\n#if defined(__hpux)\n# pragma message(HUNTER_INFO(__hpux))\n#endif\n\n#if defined(__i386)\n# pragma message(HUNTER_INFO(__i386))\n#endif\n\n#if defined(__i386__)\n# pragma message(HUNTER_INFO(__i386__))\n#endif\n\n#if defined(__i486__)\n# pragma message(HUNTER_INFO(__i486__))\n#endif\n\n#if defined(__i586__)\n# pragma message(HUNTER_INFO(__i586__))\n#endif\n\n#if defined(__i686__)\n# pragma message(HUNTER_INFO(__i686__))\n#endif\n\n#if defined(__ia64)\n# pragma message(HUNTER_INFO(__ia64))\n#endif\n\n#if defined(__ia64__)\n# pragma message(HUNTER_INFO(__ia64__))\n#endif\n\n#if defined(__itanium__)\n# pragma message(HUNTER_INFO(__itanium__))\n#endif\n\n#if defined(__k8)\n# pragma message(HUNTER_INFO(__k8))\n#endif\n\n#if defined(__k8__)\n# pragma message(HUNTER_INFO(__k8__))\n#endif\n\n#if defined(__linux)\n# pragma message(HUNTER_INFO(__linux))\n#endif\n\n#if defined(__linux__)\n# pragma message(HUNTER_INFO(__linux__))\n#endif\n\n#if defined(__llvm__)\n# pragma message(HUNTER_INFO(__llvm__))\n#endif\n\n#if defined(__m68k__)\n# pragma message(HUNTER_INFO(__m68k__))\n#endif\n\n#if defined(__mc68000)\n# pragma message(HUNTER_INFO(__mc68000))\n#endif\n\n#if defined(__mc68000__)\n# pragma message(HUNTER_INFO(__mc68000__))\n#endif\n\n#if defined(__mc68010)\n# pragma message(HUNTER_INFO(__mc68010))\n#endif\n\n#if defined(__mc68010__)\n# pragma message(HUNTER_INFO(__mc68010__))\n#endif\n\n#if defined(__mc68020)\n# pragma message(HUNTER_INFO(__mc68020))\n#endif\n\n#if defined(__mc68020__)\n# pragma message(HUNTER_INFO(__mc68020__))\n#endif\n\n#if defined(__mc68030)\n# pragma message(HUNTER_INFO(__mc68030))\n#endif\n\n#if defined(__mc68030__)\n# pragma message(HUNTER_INFO(__mc68030__))\n#endif\n\n#if defined(__mc68040)\n# pragma message(HUNTER_INFO(__mc68040))\n#endif\n\n#if defined(__mc68040__)\n# pragma message(HUNTER_INFO(__mc68040__))\n#endif\n\n#if defined(__mc68060)\n# pragma message(HUNTER_INFO(__mc68060))\n#endif\n\n#if defined(__mc68060__)\n# pragma message(HUNTER_INFO(__mc68060__))\n#endif\n\n#if defined(__mips)\n# pragma message(HUNTER_INFO(__mips))\n#endif\n\n#if defined(__mips__)\n# pragma message(HUNTER_INFO(__mips__))\n#endif\n\n#if defined(__nocona)\n# pragma message(HUNTER_INFO(__nocona))\n#endif\n\n#if defined(__nocona__)\n# pragma message(HUNTER_INFO(__nocona__))\n#endif\n\n#if defined(__pic__)\n# pragma message(HUNTER_INFO(__pic__))\n#endif\n\n#if defined(__pie__)\n# pragma message(HUNTER_INFO(__pie__))\n#endif\n\n#if defined(__powerpc)\n# pragma message(HUNTER_INFO(__powerpc))\n#endif\n\n#if defined(__powerpc__)\n# pragma message(HUNTER_INFO(__powerpc__))\n#endif\n\n#if defined(__ppc601__)\n# pragma message(HUNTER_INFO(__ppc601__))\n#endif\n\n#if defined(__ppc603__)\n# pragma message(HUNTER_INFO(__ppc603__))\n#endif\n\n#if defined(__ppc604__)\n# pragma message(HUNTER_INFO(__ppc604__))\n#endif\n\n#if defined(__ppc__)\n# pragma message(HUNTER_INFO(__ppc__))\n#endif\n\n#if defined(__private_extern__)\n# pragma message(HUNTER_INFO(__private_extern__))\n#endif\n\n#if defined(__s390__)\n# pragma message(HUNTER_INFO(__s390__))\n#endif\n\n#if defined(__s390x__)\n# pragma message(HUNTER_INFO(__s390x__))\n#endif\n\n#if defined(__sgi)\n# pragma message(HUNTER_INFO(__sgi))\n#endif\n\n#if defined(__sh1__)\n# pragma message(HUNTER_INFO(__sh1__))\n#endif\n\n#if defined(__sh2__)\n# pragma message(HUNTER_INFO(__sh2__))\n#endif\n\n#if defined(__sh3__)\n# pragma message(HUNTER_INFO(__sh3__))\n#endif\n\n#if defined(__sh__)\n# pragma message(HUNTER_INFO(__sh__))\n#endif\n\n#if defined(__sparc)\n# pragma message(HUNTER_INFO(__sparc))\n#endif\n\n#if defined(__sparc__)\n# pragma message(HUNTER_INFO(__sparc__))\n#endif\n\n#if defined(__sparcv8)\n# pragma message(HUNTER_INFO(__sparcv8))\n#endif\n\n#if defined(__sparcv9)\n# pragma message(HUNTER_INFO(__sparcv9))\n#endif\n\n#if defined(__strong)\n# pragma message(HUNTER_INFO(__strong))\n#endif\n\n#if defined(__sun)\n# pragma message(HUNTER_INFO(__sun))\n#endif\n\n#if defined(__svr4__)\n# pragma message(HUNTER_INFO(__svr4__))\n#endif\n\n#if defined(__sysv__)\n# pragma message(HUNTER_INFO(__sysv__))\n#endif\n\n#if defined(__thumb2__)\n# pragma message(HUNTER_INFO(__thumb2__))\n#endif\n\n#if defined(__thumb__)\n# pragma message(HUNTER_INFO(__thumb__))\n#endif\n\n#if defined(__tune_core2__)\n# pragma message(HUNTER_INFO(__tune_core2__))\n#endif\n\n#if defined(__tune_nocona__)\n# pragma message(HUNTER_INFO(__tune_nocona__))\n#endif\n\n#if defined(__unix)\n# pragma message(HUNTER_INFO(__unix))\n#endif\n\n#if defined(__unix__)\n# pragma message(HUNTER_INFO(__unix__))\n#endif\n\n#if defined(__unsafe_unretained)\n# pragma message(HUNTER_INFO(__unsafe_unretained))\n#endif\n\n#if defined(__weak)\n# pragma message(HUNTER_INFO(__weak))\n#endif\n\n#if defined(__x86_64)\n# pragma message(HUNTER_INFO(__x86_64))\n#endif\n\n#if defined(__x86_64__)\n# pragma message(HUNTER_INFO(__x86_64__))\n#endif\n\n#if defined(__xlC__)\n# pragma message(HUNTER_INFO(__xlC__))\n#endif\n\n#if defined(__xlc__)\n# pragma message(HUNTER_INFO(__xlc__))\n#endif\n\n#if defined(_hpux)\n# pragma message(HUNTER_INFO(_hpux))\n#endif\n\n#if defined(__has_feature)\n# if __has_feature(address_sanitizer)\n#  pragma message(HUNTER_INFO(__HUNTER_DETECT_FEATURE_address_sanitizer))\n# endif\n#endif\n\n#if defined(__has_feature)\n# if __has_feature(memory_sanitizer)\n#  pragma message(HUNTER_INFO(__HUNTER_DETECT_FEATURE_memory_sanitizer))\n# endif\n#endif\n\n#if defined(__has_feature)\n# if __has_feature(thread_sanitizer)\n#  pragma message(HUNTER_INFO(__HUNTER_DETECT_FEATURE_thread_sanitizer))\n# endif\n#endif\n\nint main() {\n}\n"
  },
  {
    "path": "scripts/append-boost-config-macros.cmake.in",
    "content": "cmake_minimum_required(VERSION 3.0)\n\n# run at the boost source root\nset(boost_user_config_file \"boost/config/user.hpp\")\n\nforeach(s @BOOST_CONFIG_MACROS@)\n  unset(append_str)\n  if(\"${s}\" MATCHES \"^([^=]+)=(.+)\" )\n    set(append_str \"#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}\")\n  else()\n    set(append_str \"#define ${s}\")\n  endif()\n  if(append_str)\n    message(\"-- append '${append_str}' to '${boost_user_config_file}'\")\n    file(APPEND \"${boost_user_config_file}\" \"\\n${append_str}\\n\")\n  endif()\nendforeach()\n"
  },
  {
    "path": "scripts/autotools-merge-lipo.cmake.in",
    "content": "# Copyright (c) 2015 Ruslan Baratov, Alexandre Pretyman\n# All rights reserved.\n\n### Input params check\n\nstring(COMPARE EQUAL \"@multi_arch_install_root@\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"multi_arch_install_root is empty\")\nendif()\n\nstring(COMPARE EQUAL \"@ios_architectures@\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"ios_architectures is empty\")\nendif()\n\nstring(COMPARE EQUAL \"@HUNTER_PACKAGE_INSTALL_PREFIX@\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"HUNTER_PACKAGE_INSTALL_PREFIX is empty\")\nendif()\n\nset(ios_architectures @ios_architectures@)\nset(built_arch_roots)\nforeach(x ${ios_architectures})\n  list(APPEND built_arch_roots @multi_arch_install_root@/${x})\nendforeach()\nlist(LENGTH ios_architectures total_arch_number)\n\n\n# We work with the first root path: we move everything, except the *.a static\n# library files into @HUNTER_PACKAGE_INSTALL_PREFIX@, then we lipo the static\n# libraries together into @HUNTER_PACKAGE_INSTALL_PREFIX@\nlist(GET built_arch_roots 0 first_built_root)\nfile(GLOB_RECURSE\n    binary_files\n    RELATIVE\n      \"${first_built_root}\"\n    ${first_built_root}/*\n)\n\nfile(GLOB_RECURSE\n    libtool_la_files\n    RELATIVE\n      \"${first_built_root}\"\n    ${first_built_root}/lib/*.la\n)\n\nfile(GLOB_RECURSE\n    text_files\n    RELATIVE\n      \"${first_built_root}\"\n    ${first_built_root}/include/*\n)\n\n# Remove all libtool_la_files from all built roots\nforeach(arch ${ios_architectures})\n  foreach(file_name ${libtool_la_files})\n    file(REMOVE\n        \"@multi_arch_install_root@/${arch}/${file_name}\"\n    )\n  endforeach()\nendforeach()\n\n# Exclude text files and .la files from binaries list\nforeach(x ${libtool_la_files})\n  list(REMOVE_ITEM binary_files ${x})\nendforeach()\n\nforeach(x ${text_files})\n  list(REMOVE_ITEM binary_files ${x})\nendforeach()\n\n# The preprocessor macros below are from\n# http://sourceforge.net/p/predef/wiki/Architectures/\n# except armv7, which was taken from:\n# clang -arch armv7 -dD -E config.h\nfunction(preprocessor_macro arch result)\n  if(${arch} STREQUAL \"armv7\")\n    set(${result} \"__ARM_ARCH_7A__\" PARENT_SCOPE)\n  elseif(${arch} STREQUAL \"armv7s\")\n    set(${result} \"__ARM_ARCH_7S__\" PARENT_SCOPE)\n  elseif(${arch} STREQUAL \"arm64\")\n    set(${result} \"__aarch64__\" PARENT_SCOPE)\n  elseif(${arch} STREQUAL \"i386\")\n    set(${result} \"__i386__\" PARENT_SCOPE)\n  elseif(${arch} STREQUAL \"x86_64\")\n    set(${result} \"__x86_64__\" PARENT_SCOPE)\n  else()\n    message(FATAL_ERROR \"Architecture: ${arch} is not supported\")\n  endif()\nendfunction()\n\n# List the different roots which ${file_name} differ from\n# ${first_built_root} and store them in result\n# If result is an empty list, all files are equal\nset(built_arch_roots_except_first ${built_arch_roots})\nlist(REMOVE_AT built_arch_roots_except_first 0)\nfunction(list_roots_file_diff file_name result)\n  # make different_roots a list, so it can be printed for better investigation\n  set(different_roots)\n  foreach(built_arch_root ${built_arch_roots_except_first})\n    file(DIFFERENT\n        is_different\n        FILES\n          \"${first_built_root}/${file_name}\"\n          \"${built_arch_root}/${file_name}\"\n    )\n    if(is_different)\n      list(APPEND different_roots \"${built_arch_root}/${file_name}\")\n    endif()\n  endforeach()\n  set(${result} ${different_roots} PARENT_SCOPE)\nendfunction()\n\n# Function is used when the files of all archs are the same, move\n# one file to the final destination and delete the others.\nfunction(move_one_delete_other file_name)\n  file(RENAME\n      \"${first_built_root}/${file_name}\"\n      \"@HUNTER_PACKAGE_INSTALL_PREFIX@/${file_name}\"\n  )\n  # Remove the unneeded copies\n  foreach(built_arch_root ${built_arch_roots_except_first})\n    file(REMOVE \"${built_arch_root}/${file_name}\")\n  endforeach()\nendfunction()\n\n\n# Merge a header file that differed in content when the project was built with\n# different architectures. Guard its contents with #ifdef #elif to guarantee\n# that each architecture gets only its file\nfunction(merge_header_diff_archs file_name)\n  set(merged_file_contents \"\n/******************************************************\n * File auto generated by Hunter by merging file:     *\n * ${file_name}\n * which differed its contents in a multi-arch build. *\n * The supported architectures are:                   *\n * ${ios_architectures}\n *****************************************************/\\n\"\n  )\n  set(arch_counter 1)\n  foreach(arch ${ios_architectures})\n    set(full_path_file_name\n        \"@multi_arch_install_root@/${arch}/${file_name}\"\n    )\n    preprocessor_macro(${arch} arch_define)\n    if (arch_counter EQUAL 1)\n      set(merged_file_contents\n          \"${merged_file_contents}\\n#ifdef ${arch_define}\\n\"\n      )\n    else()\n      set(merged_file_contents\n          \"${merged_file_contents}\\n#elif ${arch_define}\\n\"\n      )\n    endif()\n    if(EXISTS \"${full_path_file_name}\")\n      file(READ\n          ${full_path_file_name}\n          file_contents\n      )\n    else()\n      set(file_contents \"\")\n    endif()\n    # Append contents to the merged file\n    set(merged_file_contents\n        \"${merged_file_contents}${file_contents}\"\n    )\n    # Discard the file\n    file(REMOVE\n        ${full_path_file_name}\n    )\n    if (${arch_counter} EQUAL ${total_arch_number})\n      set(merged_file_contents\n          \"${merged_file_contents}\n#else\n# error Architecture not supported. It is not one of ${ios_architectures}\n#endif\\n\"\n      )\n    endif()\n    math(EXPR arch_counter ${arch_counter}+1)\n  endforeach()\n  file(WRITE\n      \"@HUNTER_PACKAGE_INSTALL_PREFIX@/${file_name}\"\n      \"${merged_file_contents}\"\n  )\nendfunction()\n\n# Compare for differences between files in built_arch_roots\n# If files are different and are in the include/ directory\n# they are merged with #ifdef guards\nforeach(file_name ${text_files})\n  get_filename_component(final_dir\n      \"@HUNTER_PACKAGE_INSTALL_PREFIX@/${file_name}\"\n      DIRECTORY\n  )\n  file(MAKE_DIRECTORY ${final_dir})\n  # List the arch roots where the file is different\n  list_roots_file_diff(${file_name} different_roots)\n  list(LENGTH different_roots len)\n  if(${len} EQUAL 0)\n    # Files are the same, so we move them to @HUNTER_PACKAGE_INSTALL_PREFIX@\n    move_one_delete_other(\"${file_name}\")\n  else()\n    # merge the file contents with #ifdef guards\n    merge_header_diff_archs(${file_name})\n  endif()\nendforeach()\n\n# we lipo the libraries into @HUNTER_PACKAGE_INSTALL_PREFIX@\nforeach(x ${binary_files})\n  # if the dir to put the library in, does not exist, then create it\n  # this is needed or else lipo could fail\n  get_filename_component(dir \"@HUNTER_PACKAGE_INSTALL_PREFIX@/${x}\" DIRECTORY)\n  file(MAKE_DIRECTORY \"${dir}\")\n\n  set(input_libraries)\n  foreach(built_arch_root ${built_arch_roots})\n    list(APPEND input_libraries ${built_arch_root}/${x})\n  endforeach()\n\n  execute_process(\n      COMMAND\n        lipo\n        -create\n        ${input_libraries}\n        -o\n        \"@HUNTER_PACKAGE_INSTALL_PREFIX@/${x}\"\n      RESULT_VARIABLE\n        lipo_result\n      ERROR_VARIABLE\n        lipo_error\n  )\n  if(NOT ${lipo_result} EQUAL 0)\n    message(FATAL_ERROR \"lipo execution failed: ${lipo_error}\")\n  endif()\n\n  file(REMOVE ${input_libraries})\nendforeach()\n\n# Check no files left (i.e. all binaries fused by lipo, all headers merged)\nfile(GLOB_RECURSE files_left \"@multi_arch_install_root@/*\")\nstring(COMPARE EQUAL \"${files_left}\" \"\" is_empty)\nif(NOT is_empty)\n  message(FATAL_ERROR \"Unexpected files: ${files_left}\")\nendif()\n"
  },
  {
    "path": "scripts/clear-all.cmake",
    "content": "unset(ENV{ACTION})\nunset(ENV{AD_HOC_CODE_SIGNING_ALLOWED})\nunset(ENV{ALTERNATE_GROUP})\nunset(ENV{ALTERNATE_MODE})\nunset(ENV{ALTERNATE_OWNER})\nunset(ENV{ALWAYS_SEARCH_USER_PATHS})\nunset(ENV{ALWAYS_USE_SEPARATE_HEADERMAPS})\nunset(ENV{APPLE_INTERNAL_DEVELOPER_DIR})\nunset(ENV{APPLE_INTERNAL_DIR})\nunset(ENV{APPLE_INTERNAL_DOCUMENTATION_DIR})\nunset(ENV{APPLE_INTERNAL_LIBRARY_DIR})\nunset(ENV{APPLE_INTERNAL_TOOLS})\nunset(ENV{APPLY_RULES_IN_COPY_FILES})\nunset(ENV{AR})\nunset(ENV{ARCHS})\nunset(ENV{ARCHS_STANDARD})\nunset(ENV{ARCHS_STANDARD_32_64_BIT})\nunset(ENV{ARCHS_STANDARD_32_BIT})\nunset(ENV{ARCHS_STANDARD_64_BIT})\nunset(ENV{ARCHS_STANDARD_INCLUDING_64_BIT})\nunset(ENV{ARCHS_UNIVERSAL_IPHONE_OS})\nunset(ENV{AVAILABLE_PLATFORMS})\nunset(ENV{BUILD_COMPONENTS})\nunset(ENV{BUILD_DIR})\nunset(ENV{BUILD_ROOT})\nunset(ENV{BUILD_STYLE})\nunset(ENV{BUILD_VARIANTS})\nunset(ENV{BUILT_PRODUCTS_DIR})\nunset(ENV{CACHE_ROOT})\nunset(ENV{CCHROOT})\nunset(ENV{CC})\nunset(ENV{CFLAGS})\nunset(ENV{CHMOD})\nunset(ENV{CHOWN})\nunset(ENV{CLASS_FILE_DIR})\nunset(ENV{CLEAN_PRECOMPS})\nunset(ENV{CLONE_HEADERS})\nunset(ENV{CODESIGNING_FOLDER_PATH})\nunset(ENV{CODE_SIGNING_ALLOWED})\nunset(ENV{CODE_SIGNING_REQUIRED})\nunset(ENV{CODE_SIGN_CONTEXT_CLASS})\nunset(ENV{COMBINE_HIDPI_IMAGES})\nunset(ENV{COMMAND_MODE})\nunset(ENV{COMPOSITE_SDK_DIRS})\nunset(ENV{COMPRESS_PNG_FILES})\nunset(ENV{CONFIGURATION_BUILD_DIR})\nunset(ENV{CONFIGURATION_TEMP_DIR})\nunset(ENV{CONFIGURATION})\nunset(ENV{CONFIG_SITE})\nunset(ENV{COPYING_PRESERVES_HFS_DATA})\nunset(ENV{COPY_PHASE_STRIP})\nunset(ENV{COPY_RESOURCES_FROM_STATIC_FRAMEWORKS})\nunset(ENV{CP})\nunset(ENV{CREATE_INFOPLIST_SECTION_IN_BINARY})\nunset(ENV{CURRENT_ARCH})\nunset(ENV{CURRENT_VARIANT})\nunset(ENV{CXX})\nunset(ENV{CXXFLAGS})\nunset(ENV{DEAD_CODE_STRIPPING})\nunset(ENV{DEBUGGING_SYMBOLS})\nunset(ENV{DEBUG_INFORMATION_FORMAT})\nunset(ENV{DEFAULT_COMPILER})\nunset(ENV{DEFAULT_KEXT_INSTALL_PATH})\nunset(ENV{DEPLOYMENT_LOCATION})\nunset(ENV{DEPLOYMENT_POSTPROCESSING})\nunset(ENV{DERIVED_FILES_DIR})\nunset(ENV{DERIVED_FILE_DIR})\nunset(ENV{DERIVED_SOURCES_DIR})\nunset(ENV{DEVELOPER_APPLICATIONS_DIR})\nunset(ENV{DEVELOPER_BIN_DIR})\n# unset(ENV{DEVELOPER_DIR}) # Used to detect Xcode environment\nunset(ENV{DEVELOPER_FRAMEWORKS_DIR_QUOTED})\nunset(ENV{DEVELOPER_FRAMEWORKS_DIR})\nunset(ENV{DEVELOPER_LIBRARY_DIR})\nunset(ENV{DEVELOPER_SDK_DIR})\nunset(ENV{DEVELOPER_TOOLS_DIR})\nunset(ENV{DEVELOPER_USR_DIR})\nunset(ENV{DEVELOPMENT_LANGUAGE})\nunset(ENV{DO_HEADER_SCANNING_IN_JAM})\nunset(ENV{DSTROOT})\nunset(ENV{DT_TOOLCHAIN_DIR})\nunset(ENV{DWARF_DSYM_FILE_NAME})\nunset(ENV{DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT})\nunset(ENV{DWARF_DSYM_FOLDER_PATH})\nunset(ENV{EFFECTIVE_PLATFORM_NAME})\nunset(ENV{EMBEDDED_PROFILE_NAME})\nunset(ENV{ENABLE_HEADER_DEPENDENCIES})\nunset(ENV{ENTITLEMENTS_REQUIRED})\nunset(ENV{EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS})\nunset(ENV{EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES})\nunset(ENV{FILE_LIST})\nunset(ENV{FIXED_FILES_DIR})\nunset(ENV{FRAMEWORK_VERSION})\nunset(ENV{GCC3_VERSION})\nunset(ENV{GCC_GENERATE_DEBUGGING_SYMBOLS})\nunset(ENV{GCC_INLINES_ARE_PRIVATE_EXTERN})\nunset(ENV{GCC_OPTIMIZATION_LEVEL})\nunset(ENV{GCC_PFE_FILE_C_DIALECTS})\nunset(ENV{GCC_PREPROCESSOR_DEFINITIONS})\nunset(ENV{GCC_SYMBOLS_PRIVATE_EXTERN})\nunset(ENV{GCC_THUMB_SUPPORT})\nunset(ENV{GCC_TREAT_WARNINGS_AS_ERRORS})\nunset(ENV{GCC_VERSION})\nunset(ENV{GCC_VERSION_IDENTIFIER})\nunset(ENV{GENERATE_MASTER_OBJECT_FILE})\nunset(ENV{GENERATE_PKGINFO_FILE})\nunset(ENV{GENERATE_PROFILING_CODE})\nunset(ENV{GID})\nunset(ENV{GROUP})\nunset(ENV{HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT})\nunset(ENV{HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES})\nunset(ENV{HEADERMAP_INCLUDES_NONPUBLIC_NONPRIVATE_HEADERS})\nunset(ENV{HEADERMAP_INCLUDES_PROJECT_HEADERS})\nunset(ENV{HEADER_SEARCH_PATHS})\nunset(ENV{ICONV})\nunset(ENV{INFOPLIST_EXPAND_BUILD_SETTINGS})\nunset(ENV{INFOPLIST_OUTPUT_FORMAT})\nunset(ENV{INFOPLIST_PREPROCESS})\nunset(ENV{INSTALL})\nunset(ENV{INSTALL_DIR})\nunset(ENV{INSTALL_GROUP})\nunset(ENV{INSTALL_MODE_FLAG})\nunset(ENV{INSTALL_OWNER})\nunset(ENV{INSTALL_ROOT})\nunset(ENV{IPHONEOS_DEPLOYMENT_TARGET}) # !\nunset(ENV{JAVAC_DEFAULT_FLAGS})\nunset(ENV{JAVA_APP_STUB})\nunset(ENV{JAVA_ARCHIVE_CLASSES})\nunset(ENV{JAVA_ARCHIVE_TYPE})\nunset(ENV{JAVA_COMPILER})\nunset(ENV{JAVA_FRAMEWORK_RESOURCES_DIRS})\nunset(ENV{JAVA_JAR_FLAGS})\nunset(ENV{JAVA_SOURCE_SUBDIR})\nunset(ENV{JAVA_USE_DEPENDENCIES})\nunset(ENV{JAVA_ZIP_FLAGS})\nunset(ENV{JIKES_DEFAULT_FLAGS})\nunset(ENV{KEEP_PRIVATE_EXTERNS})\nunset(ENV{LD})\nunset(ENV{LDFLAGS})\nunset(ENV{LD_DEPENDENCY_INFO_FILE})\nunset(ENV{LD_GENERATE_MAP_FILE})\nunset(ENV{LD_MAP_FILE_PATH})\nunset(ENV{LD_NO_PIE})\nunset(ENV{LD_QUOTE_LINKER_ARGUMENTS_FOR_COMPILER_DRIVER})\nunset(ENV{LEGACY_DEVELOPER_DIR})\nunset(ENV{LEX})\nunset(ENV{LIBRARY_FLAG_NOSPACE})\nunset(ENV{LIBRARY_KEXT_INSTALL_PATH})\nunset(ENV{LINKER_DISPLAYS_MANGLED_NAMES})\nunset(ENV{LINK_FILE_LIST_normal_armv7})\nunset(ENV{LINK_WITH_STANDARD_LIBRARIES})\nunset(ENV{LOCAL_ADMIN_APPS_DIR})\nunset(ENV{LOCAL_APPS_DIR})\nunset(ENV{LOCAL_DEVELOPER_DIR})\nunset(ENV{LOCAL_LIBRARY_DIR})\nunset(ENV{MAC_OS_X_PRODUCT_BUILD_VERSION})\nunset(ENV{MAC_OS_X_VERSION_ACTUAL})\nunset(ENV{MAC_OS_X_VERSION_MAJOR})\nunset(ENV{MAC_OS_X_VERSION_MINOR})\nunset(ENV{MAKEFLAGS})\nunset(ENV{MAKELEVEL})\nunset(ENV{MFLAGS})\nunset(ENV{MODULE_CACHE_DIR})\nunset(ENV{NATIVE_ARCH})\nunset(ENV{NATIVE_ARCH_32_BIT})\nunset(ENV{NATIVE_ARCH_64_BIT})\nunset(ENV{NATIVE_ARCH_ACTUAL})\nunset(ENV{NO_COMMON})\nunset(ENV{OBJDUMP})\nunset(ENV{OBJECT_FILE_DIR})\nunset(ENV{OBJECT_FILE_DIR_normal})\nunset(ENV{OBJROOT})\nunset(ENV{ONLY_ACTIVE_ARCH})\nunset(ENV{OPTIMIZATION_LEVEL})\nunset(ENV{OS})\nunset(ENV{OSAC})\nunset(ENV{OTHER_CFLAGS})\nunset(ENV{OTHER_CPLUSPLUSFLAGS})\nunset(ENV{OTHER_LDFLAGS})\nunset(ENV{PASCAL_STRINGS})\nunset(ENV{PATH_PREFIXES_EXCLUDED_FROM_HEADER_DEPENDENCIES})\nunset(ENV{PKGINFO_FILE_PATH})\nunset(ENV{PLATFORM_DEVELOPER_APPLICATIONS_DIR})\nunset(ENV{PLATFORM_DEVELOPER_BIN_DIR})\nunset(ENV{PLATFORM_DEVELOPER_LIBRARY_DIR})\nunset(ENV{PLATFORM_DEVELOPER_SDK_DIR})\nunset(ENV{PLATFORM_DEVELOPER_TOOLS_DIR})\nunset(ENV{PLATFORM_DEVELOPER_USR_DIR})\nunset(ENV{PLATFORM_DIR})\nunset(ENV{PLATFORM_NAME})\nunset(ENV{PLATFORM_PREFERRED_ARCH})\nunset(ENV{PLATFORM_PRODUCT_BUILD_VERSION})\nunset(ENV{PLIST_FILE_OUTPUT_FORMAT})\nunset(ENV{PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR})\nunset(ENV{PRECOMP_DESTINATION_DIR})\nunset(ENV{PRESERVE_DEAD_CODE_INITS_AND_TERMS})\nunset(ENV{PRODUCT_NAME})\nunset(ENV{PRODUCT_SETTINGS_PATH})\nunset(ENV{PROFILING_CODE})\nunset(ENV{PROJECT})\nunset(ENV{PROJECT_DERIVED_FILE_DIR})\nunset(ENV{PROJECT_DIR})\nunset(ENV{PROJECT_FILE_PATH})\nunset(ENV{PROJECT_NAME})\nunset(ENV{PROJECT_TEMP_DIR})\nunset(ENV{PROJECT_TEMP_ROOT})\nunset(ENV{RANLIB})\nunset(ENV{RC})\nunset(ENV{RECURSIVE_SEARCH_PATHS_FOLLOW_SYMLINKS})\nunset(ENV{REMOVE_CVS_FROM_RESOURCES})\nunset(ENV{REMOVE_GIT_FROM_RESOURCES})\nunset(ENV{REMOVE_HG_FROM_RESOURCES})\nunset(ENV{REMOVE_SVN_FROM_RESOURCES})\nunset(ENV{REZ_COLLECTOR_DIR})\nunset(ENV{REZ_OBJECTS_DIR})\nunset(ENV{SCAN_ALL_SOURCE_FILES_FOR_INCLUDES})\nunset(ENV{SCRIPT_INPUT_FILE_COUNT})\nunset(ENV{SCRIPT_OUTPUT_FILE_COUNT})\nunset(ENV{SDKROOT}) # !\nunset(ENV{SDK_DIR})\nunset(ENV{SDK_NAME})\nunset(ENV{SDK_PRODUCT_BUILD_VERSION})\nunset(ENV{SED})\nunset(ENV{SEPARATE_STRIP})\nunset(ENV{SEPARATE_SYMBOL_EDIT})\nunset(ENV{SET_DIR_MODE_OWNER_GROUP})\nunset(ENV{SET_FILE_MODE_OWNER_GROUP})\nunset(ENV{SHARED_DERIVED_FILE_DIR})\nunset(ENV{SHARED_PRECOMPS_DIR})\nunset(ENV{SKIP_INSTALL})\nunset(ENV{SOURCE_ROOT})\nunset(ENV{SRCROOT})\nunset(ENV{STRINGS_FILE_OUTPUT_ENCODING})\nunset(ENV{STRIP})\nunset(ENV{STRIP_INSTALLED_PRODUCT})\nunset(ENV{STRIP_STYLE})\nunset(ENV{SUPPORTED_DEVICE_FAMILIES})\nunset(ENV{SUPPORTED_PLATFORMS})\nunset(ENV{SYMROOT})\nunset(ENV{SYSTEM_ADMIN_APPS_DIR})\nunset(ENV{SYSTEM_APPS_DIR})\nunset(ENV{SYSTEM_CORE_SERVICES_DIR})\nunset(ENV{SYSTEM_DEMOS_DIR})\nunset(ENV{SYSTEM_DEVELOPER_APPS_DIR})\nunset(ENV{SYSTEM_DEVELOPER_BIN_DIR})\nunset(ENV{SYSTEM_DEVELOPER_DEMOS_DIR})\nunset(ENV{SYSTEM_DEVELOPER_DIR})\nunset(ENV{SYSTEM_DEVELOPER_DOC_DIR})\nunset(ENV{SYSTEM_DEVELOPER_GRAPHICS_TOOLS_DIR})\nunset(ENV{SYSTEM_DEVELOPER_JAVA_TOOLS_DIR})\nunset(ENV{SYSTEM_DEVELOPER_PERFORMANCE_TOOLS_DIR})\nunset(ENV{SYSTEM_DEVELOPER_RELEASENOTES_DIR})\nunset(ENV{SYSTEM_DEVELOPER_TOOLS})\nunset(ENV{SYSTEM_DEVELOPER_TOOLS_DOC_DIR})\nunset(ENV{SYSTEM_DEVELOPER_TOOLS_RELEASENOTES_DIR})\nunset(ENV{SYSTEM_DEVELOPER_USR_DIR})\nunset(ENV{SYSTEM_DEVELOPER_UTILITIES_DIR})\nunset(ENV{SYSTEM_DOCUMENTATION_DIR})\nunset(ENV{SYSTEM_KEXT_INSTALL_PATH})\nunset(ENV{SYSTEM_LIBRARY_DIR})\nunset(ENV{TARGETED_DEVICE_FAMILY})\nunset(ENV{TARGETNAME})\nunset(ENV{TARGET_BUILD_DIR})\nunset(ENV{TARGET_NAME})\nunset(ENV{TARGET_TEMP_DIR})\nunset(ENV{TEMP_DIR})\nunset(ENV{TEMP_FILES_DIR})\nunset(ENV{TEMP_FILE_DIR})\nunset(ENV{TEMP_ROOT})\nunset(ENV{TEST}) # Break Makefile OpenSSL build\nunset(ENV{TOOLCHAINS})\nunset(ENV{UNSTRIPPED_PRODUCT})\nunset(ENV{USER_APPS_DIR})\nunset(ENV{USER_LIBRARY_DIR})\nunset(ENV{USE_DYNAMIC_NO_PIC})\nunset(ENV{USE_HEADERMAP})\nunset(ENV{USE_HEADER_SYMLINKS})\nunset(ENV{VALIDATE_PRODUCT})\nunset(ENV{VALID_ARCHS})\nunset(ENV{VERBOSE_PBXCP})\nunset(ENV{VERSION_INFO_BUILDER})\nunset(ENV{VERSION_INFO_FILE})\nunset(ENV{VERSION_INFO_STRING})\nunset(ENV{WARNING_CFLAGS})\nunset(ENV{XCODE_APP_SUPPORT_DIR})\nunset(ENV{XCODE_PRODUCT_BUILD_VERSION})\nunset(ENV{XCODE_VERSION_ACTUAL})\nunset(ENV{XCODE_VERSION_MAJOR})\nunset(ENV{XCODE_VERSION_MINOR})\nunset(ENV{XPCSERVICES_FOLDER_PATH})\nunset(ENV{YACC})\nunset(ENV{arch})\nunset(ENV{variant})\n\nif(CMAKE_HOST_UNIX)\n  # Problems with Xcode and boost\n  set(ENV{PATH} \"/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin\")\nendif()\n\n# See bug https://github.com/headupinclouds/gatherer/issues/58\nunset(ENV{ANDROID_SDK_ROOT})\nunset(ENV{ANDROID_API_VERSION})\nunset(ENV{ANDROID_HOME})\n\n# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android\nunset(ENV{ANDROID_NDK})\nunset(ENV{ANDROID_NDK_ROOT})\nunset(ENV{ANDROID_STANDALONE_TOOLCHAIN})\n\n# See clear-all.sh for more info {\nunset(ENV{PKG_CONFIG_PATH})\nunset(ENV{PKG_CONFIG_DEBUG_SPEW})\nunset(ENV{PKG_CONFIG_TOP_BUILD_DIR})\nunset(ENV{PKG_CONFIG_DISABLE_UNINSTALLED})\nunset(ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS})\nunset(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS})\nunset(ENV{PKG_CONFIG_SYSROOT_DIR})\nset(ENV{PKG_CONFIG_LIBDIR} \"\")\n# }\n"
  },
  {
    "path": "scripts/clear-all.sh",
    "content": "unset ACTION\nunset AD_HOC_CODE_SIGNING_ALLOWED\nunset ALTERNATE_GROUP\nunset ALTERNATE_MODE\nunset ALTERNATE_OWNER\nunset ALWAYS_SEARCH_USER_PATHS\nunset ALWAYS_USE_SEPARATE_HEADERMAPS\nunset APPLE_INTERNAL_DEVELOPER_DIR\nunset APPLE_INTERNAL_DIR\nunset APPLE_INTERNAL_DOCUMENTATION_DIR\nunset APPLE_INTERNAL_LIBRARY_DIR\nunset APPLE_INTERNAL_TOOLS\nunset APPLY_RULES_IN_COPY_FILES\nunset AR\nunset ARCHS\nunset ARCHS_STANDARD\nunset ARCHS_STANDARD_32_64_BIT\nunset ARCHS_STANDARD_32_BIT\nunset ARCHS_STANDARD_64_BIT\nunset ARCHS_STANDARD_INCLUDING_64_BIT\nunset ARCHS_UNIVERSAL_IPHONE_OS\nunset AVAILABLE_PLATFORMS\nunset BUILD_COMPONENTS\nunset BUILD_DIR\nunset BUILD_ROOT\nunset BUILD_STYLE\nunset BUILD_VARIANTS\nunset BUILT_PRODUCTS_DIR\nunset CACHE_ROOT\nunset CC\nunset CCHROOT\nunset CFLAGS\nunset CHMOD\nunset CHOWN\nunset CLASS_FILE_DIR\nunset CLEAN_PRECOMPS\nunset CLONE_HEADERS\nunset CODESIGNING_FOLDER_PATH\nunset CODE_SIGNING_ALLOWED\nunset CODE_SIGNING_REQUIRED\nunset CODE_SIGN_CONTEXT_CLASS\nunset COMBINE_HIDPI_IMAGES\nunset COMMAND_MODE\nunset COMPOSITE_SDK_DIRS\nunset COMPRESS_PNG_FILES\nunset CONFIGURATION\nunset CONFIGURATION_BUILD_DIR\nunset CONFIGURATION_TEMP_DIR\nunset CONFIG_SITE\nunset COPYING_PRESERVES_HFS_DATA\nunset COPY_PHASE_STRIP\nunset COPY_RESOURCES_FROM_STATIC_FRAMEWORKS\nunset CP\nunset CREATE_INFOPLIST_SECTION_IN_BINARY\nunset CURRENT_ARCH\nunset CURRENT_VARIANT\nunset CXX\nunset CXXFLAGS\nunset DEAD_CODE_STRIPPING\nunset DEBUGGING_SYMBOLS\nunset DEBUG_INFORMATION_FORMAT\nunset DEFAULT_COMPILER\nunset DEFAULT_KEXT_INSTALL_PATH\nunset DEPLOYMENT_LOCATION\nunset DEPLOYMENT_POSTPROCESSING\nunset DERIVED_FILES_DIR\nunset DERIVED_FILE_DIR\nunset DERIVED_SOURCES_DIR\nunset DEVELOPER_APPLICATIONS_DIR\nunset DEVELOPER_BIN_DIR\n# unset DEVELOPER_DIR # Used to detect Xcode environment\nunset DEVELOPER_FRAMEWORKS_DIR\nunset DEVELOPER_FRAMEWORKS_DIR_QUOTED\nunset DEVELOPER_LIBRARY_DIR\nunset DEVELOPER_SDK_DIR\nunset DEVELOPER_TOOLS_DIR\nunset DEVELOPER_USR_DIR\nunset DEVELOPMENT_LANGUAGE\nunset DO_HEADER_SCANNING_IN_JAM\nunset DSTROOT\nunset DT_TOOLCHAIN_DIR\nunset DWARF_DSYM_FILE_NAME\nunset DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT\nunset DWARF_DSYM_FOLDER_PATH\nunset EFFECTIVE_PLATFORM_NAME\nunset EMBEDDED_PROFILE_NAME\nunset ENABLE_HEADER_DEPENDENCIES\nunset ENTITLEMENTS_REQUIRED\nunset EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS\nunset EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES\nunset FILE_LIST\nunset FIXED_FILES_DIR\nunset FRAMEWORK_VERSION\nunset GCC3_VERSION\nunset GCC_GENERATE_DEBUGGING_SYMBOLS\nunset GCC_INLINES_ARE_PRIVATE_EXTERN\nunset GCC_OPTIMIZATION_LEVEL\nunset GCC_PFE_FILE_C_DIALECTS\nunset GCC_PREPROCESSOR_DEFINITIONS\nunset GCC_SYMBOLS_PRIVATE_EXTERN\nunset GCC_THUMB_SUPPORT\nunset GCC_TREAT_WARNINGS_AS_ERRORS\nunset GCC_VERSION\nunset GCC_VERSION_IDENTIFIER\nunset GENERATE_MASTER_OBJECT_FILE\nunset GENERATE_PKGINFO_FILE\nunset GENERATE_PROFILING_CODE\nunset GID\nunset GROUP\nunset HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT\nunset HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES\nunset HEADERMAP_INCLUDES_NONPUBLIC_NONPRIVATE_HEADERS\nunset HEADERMAP_INCLUDES_PROJECT_HEADERS\nunset HEADER_SEARCH_PATHS\nunset ICONV\nunset INFOPLIST_EXPAND_BUILD_SETTINGS\nunset INFOPLIST_OUTPUT_FORMAT\nunset INFOPLIST_PREPROCESS\nunset INSTALL\nunset INSTALL_DIR\nunset INSTALL_GROUP\nunset INSTALL_MODE_FLAG\nunset INSTALL_OWNER\nunset INSTALL_ROOT\nunset IPHONEOS_DEPLOYMENT_TARGET # !\nunset JAVAC_DEFAULT_FLAGS\nunset JAVA_APP_STUB\nunset JAVA_ARCHIVE_CLASSES\nunset JAVA_ARCHIVE_TYPE\nunset JAVA_COMPILER\nunset JAVA_FRAMEWORK_RESOURCES_DIRS\nunset JAVA_JAR_FLAGS\nunset JAVA_SOURCE_SUBDIR\nunset JAVA_USE_DEPENDENCIES\nunset JAVA_ZIP_FLAGS\nunset JIKES_DEFAULT_FLAGS\nunset KEEP_PRIVATE_EXTERNS\nunset LD\nunset LDFLAGS\nunset LD_DEPENDENCY_INFO_FILE\nunset LD_GENERATE_MAP_FILE\nunset LD_MAP_FILE_PATH\nunset LD_NO_PIE\nunset LD_QUOTE_LINKER_ARGUMENTS_FOR_COMPILER_DRIVER\nunset LEGACY_DEVELOPER_DIR\nunset LEX\nunset LIBRARY_FLAG_NOSPACE\nunset LIBRARY_KEXT_INSTALL_PATH\nunset LINKER_DISPLAYS_MANGLED_NAMES\nunset LINK_FILE_LIST_normal_armv7\nunset LINK_WITH_STANDARD_LIBRARIES\nunset LOCAL_ADMIN_APPS_DIR\nunset LOCAL_APPS_DIR\nunset LOCAL_DEVELOPER_DIR\nunset LOCAL_LIBRARY_DIR\nunset MAC_OS_X_PRODUCT_BUILD_VERSION\nunset MAC_OS_X_VERSION_ACTUAL\nunset MAC_OS_X_VERSION_MAJOR\nunset MAC_OS_X_VERSION_MINOR\nunset MAKEFLAGS\nunset MAKELEVEL\nunset MFLAGS\nunset MODULE_CACHE_DIR\nunset NATIVE_ARCH\nunset NATIVE_ARCH_32_BIT\nunset NATIVE_ARCH_64_BIT\nunset NATIVE_ARCH_ACTUAL\nunset NO_COMMON\nunset OBJDUMP\nunset OBJECT_FILE_DIR\nunset OBJECT_FILE_DIR_normal\nunset OBJROOT\nunset ONLY_ACTIVE_ARCH\nunset OPTIMIZATION_LEVEL\nunset OS\nunset OSAC\nunset OTHER_CFLAGS\nunset OTHER_CPLUSPLUSFLAGS\nunset OTHER_LDFLAGS\nunset PASCAL_STRINGS\nunset PATH_PREFIXES_EXCLUDED_FROM_HEADER_DEPENDENCIES\nunset PKGINFO_FILE_PATH\nunset PLATFORM_DEVELOPER_APPLICATIONS_DIR\nunset PLATFORM_DEVELOPER_BIN_DIR\nunset PLATFORM_DEVELOPER_LIBRARY_DIR\nunset PLATFORM_DEVELOPER_SDK_DIR\nunset PLATFORM_DEVELOPER_TOOLS_DIR\nunset PLATFORM_DEVELOPER_USR_DIR\nunset PLATFORM_DIR\nunset PLATFORM_NAME\nunset PLATFORM_PREFERRED_ARCH\nunset PLATFORM_PRODUCT_BUILD_VERSION\nunset PLIST_FILE_OUTPUT_FORMAT\nunset PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR\nunset PRECOMP_DESTINATION_DIR\nunset PRESERVE_DEAD_CODE_INITS_AND_TERMS\nunset PRODUCT_NAME\nunset PRODUCT_SETTINGS_PATH\nunset PROFILING_CODE\nunset PROJECT\nunset PROJECT_DERIVED_FILE_DIR\nunset PROJECT_DIR\nunset PROJECT_FILE_PATH\nunset PROJECT_NAME\nunset PROJECT_TEMP_DIR\nunset PROJECT_TEMP_ROOT\nunset RANLIB\nunset RECURSIVE_SEARCH_PATHS_FOLLOW_SYMLINKS\nunset REMOVE_CVS_FROM_RESOURCES\nunset REMOVE_GIT_FROM_RESOURCES\nunset REMOVE_HG_FROM_RESOURCES\nunset REMOVE_SVN_FROM_RESOURCES\nunset REZ_COLLECTOR_DIR\nunset REZ_OBJECTS_DIR\nunset SCAN_ALL_SOURCE_FILES_FOR_INCLUDES\nunset SCRIPT_INPUT_FILE_COUNT\nunset SCRIPT_OUTPUT_FILE_COUNT\nunset SDKROOT # !\nunset SDK_DIR\nunset SDK_NAME\nunset SDK_PRODUCT_BUILD_VERSION\nunset SED\nunset SEPARATE_STRIP\nunset SEPARATE_SYMBOL_EDIT\nunset SET_DIR_MODE_OWNER_GROUP\nunset SET_FILE_MODE_OWNER_GROUP\nunset SHARED_DERIVED_FILE_DIR\nunset SHARED_PRECOMPS_DIR\nunset SKIP_INSTALL\nunset SOURCE_ROOT\nunset SRCROOT\nunset STRINGS_FILE_OUTPUT_ENCODING\nunset STRIP\nunset STRIP_INSTALLED_PRODUCT\nunset STRIP_STYLE\nunset SUPPORTED_DEVICE_FAMILIES\nunset SUPPORTED_PLATFORMS\nunset SYMROOT\nunset SYSTEM_ADMIN_APPS_DIR\nunset SYSTEM_APPS_DIR\nunset SYSTEM_CORE_SERVICES_DIR\nunset SYSTEM_DEMOS_DIR\nunset SYSTEM_DEVELOPER_APPS_DIR\nunset SYSTEM_DEVELOPER_BIN_DIR\nunset SYSTEM_DEVELOPER_DEMOS_DIR\nunset SYSTEM_DEVELOPER_DIR\nunset SYSTEM_DEVELOPER_DOC_DIR\nunset SYSTEM_DEVELOPER_GRAPHICS_TOOLS_DIR\nunset SYSTEM_DEVELOPER_JAVA_TOOLS_DIR\nunset SYSTEM_DEVELOPER_PERFORMANCE_TOOLS_DIR\nunset SYSTEM_DEVELOPER_RELEASENOTES_DIR\nunset SYSTEM_DEVELOPER_TOOLS\nunset SYSTEM_DEVELOPER_TOOLS_DOC_DIR\nunset SYSTEM_DEVELOPER_TOOLS_RELEASENOTES_DIR\nunset SYSTEM_DEVELOPER_USR_DIR\nunset SYSTEM_DEVELOPER_UTILITIES_DIR\nunset SYSTEM_DOCUMENTATION_DIR\nunset SYSTEM_KEXT_INSTALL_PATH\nunset SYSTEM_LIBRARY_DIR\nunset TARGETED_DEVICE_FAMILY\nunset TARGETNAME\nunset TARGET_BUILD_DIR\nunset TARGET_NAME\nunset TARGET_TEMP_DIR\nunset TEMP_DIR\nunset TEMP_FILES_DIR\nunset TEMP_FILE_DIR\nunset TEMP_ROOT\nunset TEST # Break Makefile OpenSSL build\nunset TOOLCHAINS\nunset UNSTRIPPED_PRODUCT\nunset USER_APPS_DIR\nunset USER_LIBRARY_DIR\nunset USE_DYNAMIC_NO_PIC\nunset USE_HEADERMAP\nunset USE_HEADER_SYMLINKS\nunset VALIDATE_PRODUCT\nunset VALID_ARCHS\nunset VERBOSE_PBXCP\nunset VERSION_INFO_BUILDER\nunset VERSION_INFO_FILE\nunset VERSION_INFO_STRING\nunset WARNING_CFLAGS\nunset XCODE_APP_SUPPORT_DIR\nunset XCODE_PRODUCT_BUILD_VERSION\nunset XCODE_VERSION_ACTUAL\nunset XCODE_VERSION_MAJOR\nunset XCODE_VERSION_MINOR\nunset XPCSERVICES_FOLDER_PATH\nunset YACC\nunset arch\nunset variant\n\n# Problems with Xcode and boost\nexport PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin\n\n# Unset environment variables used by pkg-config {\n# * http://linux.die.net/man/1/pkg-config\nunset PKG_CONFIG_PATH\nunset PKG_CONFIG_DEBUG_SPEW\nunset PKG_CONFIG_TOP_BUILD_DIR\nunset PKG_CONFIG_DISABLE_UNINSTALLED\nunset PKG_CONFIG_ALLOW_SYSTEM_CFLAGS\nunset PKG_CONFIG_ALLOW_SYSTEM_LIBS\nunset PKG_CONFIG_SYSROOT_DIR\n\n# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android\nunset ANDROID_NDK\nunset ANDROID_NDK_ROOT\nunset ANDROID_STANDALONE_TOOLCHAIN\n\n# This variable should be set to empty.\n# Example from Ubuntu:\n# > (unset PKG_CONFIG_LIBDIR && pkg-config --cflags xorg-wacom) # return default path!\n# > (export PKG_CONFIG_LIBDIR=\"\" && pkg-config --cflags xorg-wacom) # nothing found\nexport PKG_CONFIG_LIBDIR=\"\"\n# }\n"
  },
  {
    "path": "scripts/copy-files.cmake",
    "content": "# Copyright (c) 2015 Ruslan Baratov\n# All rights reserved.\n\nstring(COMPARE EQUAL \"${from}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"'from' should not be empty\")\nendif()\n\nstring(COMPARE EQUAL \"${to}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"'to' should not be empty\")\nendif()\n\nif(NOT EXISTS \"${from}\")\n  message(FATAL_ERROR \"Directory not exists: ${from}\")\nendif()\n\nif(NOT IS_DIRECTORY \"${from}\")\n  message(FATAL_ERROR \"Is not directory: ${from}\")\nendif()\n\nfile(GLOB files \"${from}/*\")\nfile(COPY ${files} DESTINATION \"${to}\")\n"
  },
  {
    "path": "scripts/create-predefined-list.py",
    "content": "#!/usr/bin/env python3\n\n# Copyright (c) 2014, Ruslan Baratov\n# All rights reserved.\n\nimport argparse\nimport os\nimport re\nimport subprocess\nimport urllib.request\n\nargparser = argparse.ArgumentParser(\n    description=\"\"\"\n        Create C++ source file `ShowPredefined.cpp` which will be used to verify\n        toolchain compatibility.\n    \"\"\"\n)\n\nargparser.add_argument(\n    '--raw',\n    help=\"\"\"\n        File with raw list of macroses (used simultaneously as initial list and\n        file to append result list)\n    \"\"\"\n)\n\nargparser.add_argument(\n    '--site',\n    help=\"\"\"\n        Read macroses <strong>_...</strong> from site.\n        Example: http://msdn.microsoft.com/en-us/library/b0084kay.aspx\n    \"\"\"\n)\n\nargparser.add_argument(\n    '--compiler',\n    help=\"\"\"\n        GCC-like unix compiler that accept syntax: '-E -x c++ -dM /dev/null'\n    \"\"\"\n)\n\nargparser.add_argument(\n    '--arch',\n    help=\"\"\"\n        Architecture for compiler (e.g. armv7, armv7s, arm64, i386, x86_64, ...)\n    \"\"\"\n)\n\nargparser.add_argument(\n    '--boost-predef',\n    action='store_true',\n    help=\"\"\"\n        Read macroses from repository: https://github.com/boostorg/predef\n    \"\"\"\n)\n\nargs = argparser.parse_args()\n\n# This macroses is not quite helpful\nexclude_list = [\n    '__DATE__',\n    '__FILE__',\n    '__LINE__',\n    '__TIME__',\n    '__TIMESTAMP__',\n    '__NO_INLINE__',\n    '_DEBUG',\n    '__FUNCTION__',\n\n    # gcc & clang preprocessor extensions\n    # see https://github.com/ruslo/hunter/pull/425\n    '__has_include',\n    '__has_include_next',\n]\n\nmacros_list = []\nif args.raw:\n  data = open(args.raw, \"r\").read()\n  macros_list += data.split()\n\nif args.site:\n  content = urllib.request.urlopen(args.site).read().decode('utf-8')\n  parsed = re.findall('<strong>_[^<]*</strong>', content)\n  for x in parsed:\n    macros_list.append(re.sub(r'<strong>(.*)</strong>', r'\\1', x))\n\nif args.boost_predef:\n  temp_dir = os.path.join(os.getcwd(), '__temp-git-predef')\n  if not os.path.exists(temp_dir):\n    subprocess.check_call(\n        ['git', 'clone', 'https://github.com/boostorg/predef', temp_dir]\n    )\n  gitdir = os.path.join(temp_dir, '.git')\n  docdir = os.path.join(temp_dir, 'doc')\n\n  assert(os.path.exists(gitdir))\n  assert(os.path.exists(docdir))\n\n  macro = re.compile(r'\\bdefined\\(_[^)]*\\)')\n  boost_macro_list = []\n  for root, dirs, files in os.walk(temp_dir):\n    if root.startswith(gitdir):\n      continue\n    if root.startswith(docdir):\n      continue\n    for x in files:\n      filename = os.path.join(root, x)\n      boost_macro_list += macro.findall(open(filename).read())\n  boost_macro_list = list(set(boost_macro_list))\n  macros_list += [\n      re.sub(r'^defined\\((.*)\\)$', r'\\1', x) for x in boost_macro_list\n  ]\n\nif args.compiler:\n  run_args = [args.compiler, '-E', '-x', 'c++', '-dM', '/dev/null']\n  if args.arch:\n    run_args += ['-arch', args.arch]\n  macroses = subprocess.check_output(run_args, universal_newlines=True)\n  compiler_macro_list = macroses.split('\\n')\n  for x in compiler_macro_list:\n    if re.match(r'^#define _', x):\n      macros_list.append(re.sub(r'^#define ([^ (]*).*', r'\\1', x))\n\nmacros_list = sorted(set(macros_list))\nfor to_exclude in exclude_list:\n  if to_exclude in macros_list:\n    macros_list.remove(to_exclude)\n\nfor x in macros_list:\n  print(\"> {}\".format(x))\n\nif args.raw:\n  result_fl = open(args.raw, 'w')\n  for macro in macros_list:\n    result_fl.write('{}\\n'.format(macro))\n\n# https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs.85).aspx\n\ncpp_head = \"\"\"\n// This file generated automatically by `create-predefined-list.py` script.\n// * https://github.com/ruslo/hunter\n\n#define HUNTER_QUOTE(x) #x\n#define HUNTER_STRING(x) HUNTER_QUOTE(x)\n#define HUNTER_INFO(x) \\\\\n    \"__HUNTER_MACRO_CHECK_BEGIN__\" \\\\\n    \"#define \" #x \" \" HUNTER_STRING(x) \\\\\n    \"__HUNTER_MACRO_CHECK_END__\"\n\n#include <exception> // Check std library version\n\n#if defined(__ANDROID__)\n# include <android/api-level.h> // Header with __ANDROID_API__\n#endif\n\n#if defined(_MSC_VER)\n# include <SdkDdkVer.h> // Header with _WIN32_WINNT\n#endif\n\"\"\"\n\ncpp_one_check = \"\"\"\n#if defined({})\n# pragma message(HUNTER_INFO({}))\n#endif\n\"\"\"\n\n# http://clang.llvm.org/docs/AddressSanitizer.html#conditional-compilation-with-has-feature-address-sanitizer\nsanitize_detect_check = \"\"\"\n#if defined(__has_feature)\n# if __has_feature({}_sanitizer)\n#  pragma message(HUNTER_INFO(__HUNTER_DETECT_FEATURE_{}_sanitizer))\n# endif\n#endif\n\"\"\"\n\nsanitizers_list = [\n    'address',\n#    'leak', # Not detected!\n    'memory',\n    'thread'\n]\n\ncpp_end = \"\"\"\nint main() {\n}\n\"\"\"\n\nif macros_list:\n  cpp_result = open('ShowPredefined.cpp', 'w')\n  cpp_result.write(cpp_head)\n  for x in macros_list:\n    cpp_result.write(cpp_one_check.format(x, x))\n  for x in sanitizers_list:\n    cpp_result.write(sanitize_detect_check.format(x, x))\n  cpp_result.write(cpp_end)\n"
  },
  {
    "path": "scripts/create-toolchain-info.cmake",
    "content": "cmake_minimum_required(VERSION 3.0)\nproject(HunterToolchain)\n\nif(NOT HUNTER_SELF)\n  # Emulate 'hunter_internal_error'\n  message(\"[hunter ** INTERNAL **] HUNTER_SELF is empty\")\n  message(\"[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]\")\n  message(\"\")\n  message(\"------------------------------ WIKI -------------------------------\")\n  message(\"    https://github.com/ruslo/hunter/wiki/error.internal\")\n  message(\"-------------------------------------------------------------------\")\n  message(FATAL_ERROR \"\")\nendif()\n\nlist(APPEND CMAKE_MODULE_PATH \"${HUNTER_SELF}/cmake/modules\")\ninclude(hunter_fatal_error)\ninclude(hunter_internal_error)\n\nif(NOT TOOLCHAIN_INFO_FILE)\n  hunter_internal_error(\"TOOLCHAIN_INFO_FILE is empty\")\nendif()\n\nif(NOT CMAKE_BINARY_DIR)\n  hunter_internal_error(\"CMAKE_BINARY_DIR empty\")\nendif()\n\nif(EXISTS \"${TOOLCHAIN_INFO_FILE}\")\n  hunter_internal_error(\"${TOOLCHAIN_INFO_FILE} already exists\")\nendif()\n\ninclude(hunter_assert_not_empty_string)\nhunter_assert_not_empty_string(\"${HUNTER_CONFIGURATION_TYPES}\")\n\nfile(\n    WRITE\n    \"${TOOLCHAIN_INFO_FILE}\"\n    \"Cache version: 6\\n\"\n    \"Polly toolchains:\\n\"\n    \"    IPHONEOS_ARCHS: ${IPHONEOS_ARCHS}\\n\"\n    \"    IPHONESIMULATOR_ARCHS: ${IPHONESIMULATOR_ARCHS}\\n\"\n    \"Other:\\n\"\n    \"    CMAKE_GENERATOR: ${CMAKE_GENERATOR}\\n\"\n    \"    HUNTER_CONFIGURATION_TYPES: ${HUNTER_CONFIGURATION_TYPES}\\n\"\n    \"    HUNTER_TOOLCHAIN_UNDETECTABLE_ID: ${HUNTER_TOOLCHAIN_UNDETECTABLE_ID}\\n\"\n)\n\nstring(COMPARE EQUAL \"${HUNTER_BUILD_SHARED_LIBS}\" \"\" is_empty)\nif(NOT is_empty)\n  file(\n      APPEND\n      \"${TOOLCHAIN_INFO_FILE}\"\n      \"    HUNTER_BUILD_SHARED_LIBS: ${HUNTER_BUILD_SHARED_LIBS}\\n\"\n  )\nendif()\n\nstring(COMPARE EQUAL \"${OSX_SDK_VERSION}\" \"\" is_empty)\nif(NOT is_empty)\n  file(\n      APPEND\n      \"${TOOLCHAIN_INFO_FILE}\"\n      \"    OSX_SDK_VERSION: ${OSX_SDK_VERSION}\\n\"\n  )\nendif()\n\nforeach(configuration ${HUNTER_CONFIGURATION_TYPES})\n  string(TOUPPER \"${configuration}\" configuration_upper)\n  file(APPEND \"${TOOLCHAIN_INFO_FILE}\" \"    CMAKE_${configuration_upper}_POSTFIX: \")\n  file(APPEND \"${TOOLCHAIN_INFO_FILE}\" \"${CMAKE_${configuration_upper}_POSTFIX}\\n\")\nendforeach()\n\nset(predefined \"${HUNTER_SELF}/scripts/ShowPredefined.cpp\")\nif(NOT EXISTS \"${predefined}\")\n  hunter_internal_error(\"${predefined} not exists\")\nendif()\n\ntry_compile(\n    try_compile_result\n    \"${CMAKE_BINARY_DIR}/_test\"\n    \"${predefined}\"\n    CMAKE_FLAGS \"-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}\"\n    OUTPUT_VARIABLE outresult\n)\n\nif(NOT try_compile_result)\n  hunter_internal_error(\n      \"Compilation of ${predefined} failed. Result: ${try_compile_result}\\n\"\n      \"Output:\\n--- OUTPUT BEGIN ---\\n${outresult}\\n--- OUTPUT END ---\"\n  )\nendif()\n\nfunction(split_string string_in result)\n  set(\"${result}\" \"\")\n\n  while(TRUE)\n    string(COMPARE EQUAL \"${string_in}\" \"\" is_empty)\n    if(is_empty)\n      break()\n    endif()\n\n    string(FIND \"${string_in}\" \"\\n\" eol_pos)\n    if(eol_pos EQUAL -1)\n      list(APPEND \"${result}\" \"${string_in}\")\n      break()\n    endif()\n\n    string(SUBSTRING \"${string_in}\" 0 ${eol_pos} substring)\n    list(APPEND \"${result}\" \"${substring}\")\n    math(EXPR eol_pos \"${eol_pos} + 1\") # Skip EOL character\n    string(SUBSTRING \"${string_in}\" ${eol_pos} -1 string_in)\n  endwhile()\n\n  set(${result} \"${${result}}\" PARENT_SCOPE)\nendfunction()\n\nsplit_string(\"${outresult}\" list_of_strings)\n\nset(macroses \"\")\nforeach(x ${list_of_strings})\n  string(\n      REGEX\n      MATCH\n      \"__HUNTER_MACRO_CHECK_BEGIN__.*__HUNTER_MACRO_CHECK_END__\"\n      result_x\n      \"${x}\"\n  )\n  if(result_x)\n    string(\n        REGEX\n        REPLACE\n        \".*__HUNTER_MACRO_CHECK_BEGIN__\\(.*\\)__HUNTER_MACRO_CHECK_END__.*\"\n        \"\\\\1\"\n        result_x\n        \"${x}\"\n    )\n    set(macroses \"${macroses}${result_x}\\n\")\n  endif()\nendforeach()\n\nstring(COMPARE EQUAL \"${macroses}\" \"\" is_empty)\nif(is_empty)\n  hunter_fatal_error(\"No toolchain info generated\" WIKI error.no.toolchain.info)\nendif()\n\nfile(APPEND \"${TOOLCHAIN_INFO_FILE}\" \"Predefined macroses:\\n${macroses}\")\n"
  },
  {
    "path": "scripts/find_python.cmake",
    "content": "cmake_minimum_required(VERSION 3.0)\n\nfind_package(PythonInterp 3 QUIET)\n\nif(NOT PYTHONINTERP_FOUND)\n  message(FATAL_ERROR \"Python not found\")\nendif()\n\nmessage(${PYTHON_EXECUTABLE})\n"
  },
  {
    "path": "scripts/link-all.cmake",
    "content": "cmake_minimum_required(VERSION 3.0)\n\nstring(COMPARE EQUAL \"${HUNTER_INSTALL_PREFIX}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"HUNTER_INSTALL_PREFIX is empty\")\nendif()\n\nif(NOT EXISTS \"${HUNTER_INSTALL_PREFIX}\")\n  message(FATAL_ERROR \"Directory not exists: ${HUNTER_INSTALL_PREFIX}\")\nendif()\n\nstring(COMPARE EQUAL \"${LIST_OF_FILES}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"LIST_OF_FILES is empty\")\nendif()\n\nif(NOT EXISTS \"${LIST_OF_FILES}\")\n  message(FATAL_ERROR \"File not exists: ${LIST_OF_FILES}\")\nendif()\n\nstring(COMPARE EQUAL \"${SHELL_LINK_SCRIPT}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"SHELL_LINK_SCRIPT is empty\")\nendif()\n\nif(NOT EXISTS \"${SHELL_LINK_SCRIPT}\")\n  message(FATAL_ERROR \"File not exists: ${SHELL_LINK_SCRIPT}\")\nendif()\n\nstring(COMPARE EQUAL \"${CELLAR_RAW_DIRECTORY}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"CELLAR_RAW_DIRECTORY is empty\")\nendif()\n\nif(NOT EXISTS \"${CELLAR_RAW_DIRECTORY}\")\n  message(FATAL_ERROR \"Directory not found: ${CELLAR_RAW_DIRECTORY}\")\nendif()\n\nstring(COMPARE EQUAL \"${PYTHON_LINK_SCRIPT}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"PYTHON_LINK_SCRIPT is empty\")\nendif()\n\nif(NOT EXISTS \"${PYTHON_LINK_SCRIPT}\")\n  message(FATAL_ERROR \"File not exists: ${PYTHON_LINK_SCRIPT}\")\nendif()\n\nfind_package(PythonInterp 3 QUIET)\nif(PYTHONINTERP_FOUND)\n  message(\"Link files using Python: ${PYTHON_EXECUTABLE}\")\n  set(\n      cmd\n      \"${PYTHON_EXECUTABLE}\"\n      \"${PYTHON_LINK_SCRIPT}\"\n      \"--list\"\n      \"${LIST_OF_FILES}\"\n      \"--cellar\"\n      \"${CELLAR_RAW_DIRECTORY}\"\n      \"--dest\"\n      \"${HUNTER_INSTALL_PREFIX}\"\n  )\n  execute_process(\n      COMMAND ${cmd}\n      WORKING_DIRECTORY \"${CELLAR_RAW_DIRECTORY}\"\n      RESULT_VARIABLE result\n      OUTPUT_VARIABLE output\n      ERROR_VARIABLE error\n  )\n  if(NOT result EQUAL 0)\n    message(\n        WARNING\n        \"Python script failed: ${cmd}, ${result}, ${output}, ${error}\"\n        \"(may help: https://stackoverflow.com/a/2009505/2288008)\"\n    )\n  else()\n    return()\n  endif()\nendif()\n\nset(shell \"/bin/bash\")\nif(EXISTS \"${shell}\")\n  message(\"Link files using shell: ${shell}\")\n  set(cmd \"${shell}\" \"${SHELL_LINK_SCRIPT}\" \"${HUNTER_INSTALL_PREFIX}\")\n  execute_process(\n      COMMAND ${cmd}\n      WORKING_DIRECTORY \"${CELLAR_RAW_DIRECTORY}\"\n      RESULT_VARIABLE result\n      OUTPUT_VARIABLE output\n      ERROR_VARIABLE error\n  )\n  if(NOT result EQUAL 0)\n    message(\n        FATAL_ERROR\n        \"Shell script failed: ${cmd}, ${result}, ${output}, ${error}\"\n    )\n  endif()\n  return()\nendif()\n\nmessage(\"Copy files\")\nfile(STRINGS \"${LIST_OF_FILES}\" files)\nforeach(x ${files})\n  set(full_dst_path \"${HUNTER_INSTALL_PREFIX}/${x}\")\n  get_filename_component(dst_dir \"${full_dst_path}\" DIRECTORY)\n  file(COPY \"${CELLAR_RAW_DIRECTORY}/${x}\" DESTINATION \"${dst_dir}\")\nendforeach()\n"
  },
  {
    "path": "scripts/link-all.py",
    "content": "#!/usr/bin/env python3\n\nimport argparse\nimport os\nimport sys\nimport multiprocessing\n\nparser = argparse.ArgumentParser(description='File link script')\n\nparser.add_argument('--list', required=True)\nparser.add_argument('--cellar', required=True)\nparser.add_argument('--dest', required=True)\n\ncmd_args = parser.parse_args()\n\nsrc_list = []\nwith open(cmd_args.list, 'r') as f:\n  for line in f:\n    src_list.append(line.strip())\n\nlist_len = len(src_list)\nproc_num = multiprocessing.cpu_count()\nfiles_per_job = list_len // proc_num\n\ndef job(job_index):\n  try:\n    begin_ind = files_per_job * job_index\n    end_ind = files_per_job * (job_index + 1)\n    last_job = (job_index == proc_num - 1)\n    if last_job:\n      end_ind = list_len\n    for i in range(begin_ind, end_ind):\n      filename = src_list[i]\n      link_from = os.path.join(cmd_args.cellar, filename)\n      link_to = os.path.join(cmd_args.dest, filename)\n      os.link(link_from, link_to)\n    return 0\n  except Exception as exc:\n    print('Exception caught: {}'.format(exc))\n    return 1\n\ndef run_link():\n  pool = multiprocessing.Pool(processes=proc_num)\n  result = pool.map(job, range(proc_num))\n  pool.close()\n  pool.join()\n\n  if 1 in result:\n    sys.exit('Some job failed')\n\nif __name__ == '__main__':\n  run_link()\n"
  },
  {
    "path": "scripts/pkgconfig-export-targets.cmake.in",
    "content": "# ----------------------------------------------------------------------\n# Auto creation of CMake targets from pkg-config\n#\n# Copyright (C) 2017 Alexandre Pretyman. All rights reserved.\n#\n# ----------------------------------------------------------------------\n\ninclude(hunter_pkgconfig_export_target)\n\nhunter_pkgconfig_export_target(\"@PKG_CONFIG_MODULE@\")\n\nforeach(_hunter_deps @DEPENDS_ON_PACKAGES@)\n  find_package(\"${_hunter_deps}\" CONFIG REQUIRED)\n\n  set_property(\n      TARGET\n      \"PkgConfig::@PKG_CONFIG_MODULE@\"\n      APPEND\n      PROPERTY\n      INTERFACE_LINK_LIBRARIES \"PkgConfig::${_hunter_deps}\"\n  )\nendforeach()\n"
  },
  {
    "path": "scripts/predefined.list",
    "content": "_ABI64\n_ABIO32\n_AIX\n_AIX3\n_AIX32\n_AIX41\n_AIX43\n_ARCH_601\n_ARCH_603\n_ARCH_PPC\n_ARCH_PWR\n_ARCH_PWR2\n_ATL_VER\n_BIG_ENDIAN\n_BYTE_ORDER\n_CHAR_UNSIGNED\n_COMPILER_VERSION\n_CONTROL_FLOW_GUARD\n_CPPLIB_VER\n_CPPRTTI\n_CPPUNWIND\n_DLL\n_GLIBCXX_USE_CXX11_ABI\n_GNU_SOURCE\n_IA64\n_IBMR2\n_INTEGRAL_MAX_BITS\n_ISO_VOLATILE\n_KERNEL_MODE\n_LIBCPP_HAS_NO_ASAN\n_LIBCPP_VERSION\n_LITTLE_ENDIAN\n_LP64\n_MANAGED\n_MFC_VER\n_MIPSEB\n_MIPSEL\n_MIPS_ISA_MIPS1\n_MIPS_ISA_MIPS2\n_MIPS_ISA_MIPS3\n_MIPS_ISA_MIPS4\n_MRI\n_MSC_BUILD\n_MSC_EXTENSIONS\n_MSC_FULL_VER\n_MSC_VER\n_MSVC_LANG\n_MT\n_M_ALPHA\n_M_AMD64\n_M_ARM\n_M_ARM64\n_M_ARM_ARMV7VE\n_M_ARM_FP\n_M_CEE\n_M_CEE_PURE\n_M_CEE_SAFE\n_M_FP_EXCEPT\n_M_FP_FAST\n_M_FP_PRECISE\n_M_FP_STRICT\n_M_IA64\n_M_IX86\n_M_IX86_FP\n_M_PPC\n_M_X64\n_NATIVE_WCHAR_T_DEFINED\n_NTO_VERSION\n_OPENMP\n_PACC_VER\n_PA_RISC1_0\n_PA_RISC1_1\n_PA_RISC2_0\n_PDP_ENDIAN\n_POSIX_SOURCE\n_POWER\n_PREFAST_\n_R3000\n_R4000\n_RWSTD_VER\n_SGI_COMPILER_VERSION\n_STDC_PREDEF_H\n_STLPORT_MAJOR\n_STLPORT_VERSION\n_SYSTYPE_BSD\n_SYSTYPE_SVR4\n_VC_NODEFAULTLIB\n_WCHAR_T_DEFINED\n_WIN32\n_WIN32_WINNT\n_WIN64\n_WINRT_DLL\n_Wp64\n_X86_\n_XENON\n_XOPEN_SOURCE\n_YVALS\n__370__\n__AARCH64EB__\n__AARCH64EL__\n__AARCH64_SIMD__\n__ACCUM_EPSILON__\n__ACCUM_FBIT__\n__ACCUM_IBIT__\n__ACCUM_MAX__\n__ACCUM_MIN__\n__ALTIVEC__\n__ANDROID_API__\n__ANDROID__\n__APCS_32__\n__APPLE_CC__\n__APPLE__\n__ARM64_ARCH_8__\n__ARMEB__\n__ARMEL__\n__ARM_32BIT_STATE\n__ARM_64BIT_STATE\n__ARM_ACLE\n__ARM_ALIGN_MAX_STACK_PWR\n__ARM_ARCH\n__ARM_ARCH_7A__\n__ARM_ARCH_7S__\n__ARM_ARCH_EXT_IDIV__\n__ARM_ARCH_ISA_A64\n__ARM_ARCH_ISA_ARM\n__ARM_ARCH_ISA_THUMB\n__ARM_ARCH_PROFILE\n__ARM_ASM_SYNTAX_UNIFIED__\n__ARM_EABI__\n__ARM_FEATURE_CLZ\n__ARM_FEATURE_CRYPTO\n__ARM_FEATURE_DIV\n__ARM_FEATURE_DSP\n__ARM_FEATURE_FMA\n__ARM_FEATURE_LDREX\n__ARM_FEATURE_QBIT\n__ARM_FEATURE_SAT\n__ARM_FEATURE_SIMD32\n__ARM_FEATURE_UNALIGNED\n__ARM_FP\n__ARM_FP16_FORMAT_IEEE\n__ARM_NEON\n__ARM_NEON_FP\n__ARM_NEON__\n__ARM_PCS_AAPCS64\n__ARM_PCS_VFP\n__ARM_SIZEOF_MINIMAL_ENUM\n__ARM_SIZEOF_WCHAR_T\n__ARM_VFPV3__\n__ARM_VFPV4__\n__ATOMIC_ACQUIRE\n__ATOMIC_ACQ_REL\n__ATOMIC_CONSUME\n__ATOMIC_HLE_ACQUIRE\n__ATOMIC_HLE_RELEASE\n__ATOMIC_RELAXED\n__ATOMIC_RELEASE\n__ATOMIC_SEQ_CST\n__ATOM__\n__AVX2__\n__AVX__\n__BEOS__\n__BFIN__\n__BIGGEST_ALIGNMENT__\n__BIG_ENDIAN\n__BIG_ENDIAN__\n__BLOCKS__\n__BORLANDC__\n__BYTE_ORDER\n__BYTE_ORDER__\n__CHAR16_TYPE__\n__CHAR32_TYPE__\n__CHAR_BIT__\n__CHAR_UNSIGNED__\n__CLR_VER\n__CODEGEARC__\n__COMO_VERSION__\n__COMO__\n__COMPILER_VER__\n__CONO_VERSION__\n__CONSTANT_CFSTRINGS__\n__COUNTER__\n__CRTL_VER\n__CWCC__\n__CYGWIN__\n__DA_FBIT__\n__DA_IBIT__\n__DBL_DECIMAL_DIG__\n__DBL_DENORM_MIN__\n__DBL_DIG__\n__DBL_EPSILON__\n__DBL_HAS_DENORM__\n__DBL_HAS_INFINITY__\n__DBL_HAS_QUIET_NAN__\n__DBL_MANT_DIG__\n__DBL_MAX_10_EXP__\n__DBL_MAX_EXP__\n__DBL_MAX__\n__DBL_MIN_10_EXP__\n__DBL_MIN_EXP__\n__DBL_MIN__\n__DCC__\n__DEC128_EPSILON__\n__DEC128_MANT_DIG__\n__DEC128_MAX_EXP__\n__DEC128_MAX__\n__DEC128_MIN_EXP__\n__DEC128_MIN__\n__DEC128_SUBNORMAL_MIN__\n__DEC32_EPSILON__\n__DEC32_MANT_DIG__\n__DEC32_MAX_EXP__\n__DEC32_MAX__\n__DEC32_MIN_EXP__\n__DEC32_MIN__\n__DEC32_SUBNORMAL_MIN__\n__DEC64_EPSILON__\n__DEC64_MANT_DIG__\n__DEC64_MAX_EXP__\n__DEC64_MAX__\n__DEC64_MIN_EXP__\n__DEC64_MIN__\n__DEC64_SUBNORMAL_MIN__\n__DECC\n__DECCXX\n__DECCXX_VER\n__DECC_VER\n__DECIMAL_BID_FORMAT__\n__DECIMAL_DIG__\n__DEC_EVAL_METHOD__\n__DEPRECATED\n__DMC__\n__DQ_FBIT__\n__DQ_IBIT__\n__DYNAMIC__\n__DragonFly__\n__ECC\n__EDG__\n__ELF__\n__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__\n__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__\n__EXCEPTIONS\n__FINITE_MATH_ONLY__\n__FLOAT_WORD_ORDER__\n__FLT_DECIMAL_DIG__\n__FLT_DENORM_MIN__\n__FLT_DIG__\n__FLT_EPSILON__\n__FLT_EVAL_METHOD__\n__FLT_HAS_DENORM__\n__FLT_HAS_INFINITY__\n__FLT_HAS_QUIET_NAN__\n__FLT_MANT_DIG__\n__FLT_MAX_10_EXP__\n__FLT_MAX_EXP__\n__FLT_MAX__\n__FLT_MIN_10_EXP__\n__FLT_MIN_EXP__\n__FLT_MIN__\n__FLT_RADIX__\n__FMA4__\n__FMA__\n__FP_FAST_FMA\n__FP_FAST_FMAF\n__FP_FAST_FMAL\n__FRACT_EPSILON__\n__FRACT_FBIT__\n__FRACT_IBIT__\n__FRACT_MAX__\n__FRACT_MIN__\n__FUNCDNAME__\n__FUNCSIG__\n__FXSR__\n__FreeBSD__\n__FreeBSD_version\n__GCCXML__\n__GCC_ASM_FLAG_OUTPUTS__\n__GCC_ATOMIC_BOOL_LOCK_FREE\n__GCC_ATOMIC_CHAR16_T_LOCK_FREE\n__GCC_ATOMIC_CHAR32_T_LOCK_FREE\n__GCC_ATOMIC_CHAR_LOCK_FREE\n__GCC_ATOMIC_INT_LOCK_FREE\n__GCC_ATOMIC_LLONG_LOCK_FREE\n__GCC_ATOMIC_LONG_LOCK_FREE\n__GCC_ATOMIC_POINTER_LOCK_FREE\n__GCC_ATOMIC_SHORT_LOCK_FREE\n__GCC_ATOMIC_TEST_AND_SET_TRUEVAL\n__GCC_ATOMIC_WCHAR_T_LOCK_FREE\n__GCC_HAVE_DWARF2_CFI_ASM\n__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1\n__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16\n__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2\n__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4\n__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8\n__GCC_IEC_559\n__GCC_IEC_559_COMPLEX\n__GHS_VERSION_NUMBER__\n__GLIBCPP__\n__GLIBCXX_BITSIZE_INT_N_0\n__GLIBCXX_TYPE_INT_N_0\n__GLIBCXX__\n__GLIBC__\n__GNUC_GNU_INLINE__\n__GNUC_LIBSTD_MINOR__\n__GNUC_LIBSTD__\n__GNUC_MINOR__\n__GNUC_PATCHLEVEL__\n__GNUC_STDC_INLINE__\n__GNUC__\n__GNUG__\n__GNU_LIBRARY__\n__GXX_ABI_VERSION\n__GXX_EXPERIMENTAL_CXX0X__\n__GXX_RTTI\n__GXX_TYPEINFO_EQUALITY_INLINE\n__GXX_WEAK__\n__HAIKU__\n__HA_FBIT__\n__HA_IBIT__\n__HIGHC__\n__HPPA11__\n__HPPA20__\n__HPPA__\n__HP_aCC\n__HQ_FBIT__\n__HQ_IBIT__\n__I86__\n__IA64__\n__IAR_SYSTEMS_ICC__\n__IBMCPP__\n__ICC\n__ICL\n__INT16_C\n__INT16_MAX__\n__INT16_TYPE__\n__INT32_C\n__INT32_MAX__\n__INT32_TYPE__\n__INT64_C\n__INT64_C_SUFFIX__\n__INT64_MAX__\n__INT64_TYPE__\n__INT8_C\n__INT8_MAX__\n__INT8_TYPE__\n__INTEL_COMPILER\n__INTEL__\n__INTMAX_C\n__INTMAX_MAX__\n__INTMAX_TYPE__\n__INTMAX_WIDTH__\n__INTPTR_MAX__\n__INTPTR_TYPE__\n__INTPTR_WIDTH__\n__INT_FAST16_MAX__\n__INT_FAST16_TYPE__\n__INT_FAST32_MAX__\n__INT_FAST32_TYPE__\n__INT_FAST64_MAX__\n__INT_FAST64_TYPE__\n__INT_FAST8_MAX__\n__INT_FAST8_TYPE__\n__INT_LEAST16_MAX__\n__INT_LEAST16_TYPE__\n__INT_LEAST32_MAX__\n__INT_LEAST32_TYPE__\n__INT_LEAST64_MAX__\n__INT_LEAST64_TYPE__\n__INT_LEAST8_MAX__\n__INT_LEAST8_TYPE__\n__INT_MAX__\n__KCC\n__LACCUM_EPSILON__\n__LACCUM_FBIT__\n__LACCUM_IBIT__\n__LACCUM_MAX__\n__LACCUM_MIN__\n__LDBL_DENORM_MIN__\n__LDBL_DIG__\n__LDBL_EPSILON__\n__LDBL_HAS_DENORM__\n__LDBL_HAS_INFINITY__\n__LDBL_HAS_QUIET_NAN__\n__LDBL_MANT_DIG__\n__LDBL_MAX_10_EXP__\n__LDBL_MAX_EXP__\n__LDBL_MAX__\n__LDBL_MIN_10_EXP__\n__LDBL_MIN_EXP__\n__LDBL_MIN__\n__LFRACT_EPSILON__\n__LFRACT_FBIT__\n__LFRACT_IBIT__\n__LFRACT_MAX__\n__LFRACT_MIN__\n__LIBCOMO__\n__LIBREL__\n__LITTLE_ENDIAN\n__LITTLE_ENDIAN__\n__LLACCUM_EPSILON__\n__LLACCUM_FBIT__\n__LLACCUM_IBIT__\n__LLACCUM_MAX__\n__LLACCUM_MIN__\n__LLFRACT_EPSILON__\n__LLFRACT_FBIT__\n__LLFRACT_IBIT__\n__LLFRACT_MAX__\n__LLFRACT_MIN__\n__LONG_LONG_MAX__\n__LONG_MAX__\n__LP64__\n__MACH__\n__MIC__\n__MINGW32_VERSION_MAJOR\n__MINGW32_VERSION_MINOR\n__MINGW32__\n__MINGW64_VERSION_MAJOR\n__MINGW64_VERSION_MINOR\n__MINGW64__\n__MIPSEB\n__MIPSEB__\n__MIPSEL\n__MIPSEL__\n__MIPS_ISA2__\n__MIPS_ISA3__\n__MIPS_ISA4__\n__MIPS__\n__MMX__\n__MRC__\n__MSIPL_COMPILE_H\n__MSL_CPP__\n__MSL__\n__MSVC_RUNTIME_CHECKS\n__MWERKS__\n__NETBSD__\n__NETBSD_version\n__NO_MATH_INLINES\n__NetBSD_Version\n__NetBSD__\n__OBJC__\n__ORDER_BIG_ENDIAN__\n__ORDER_LITTLE_ENDIAN__\n__ORDER_PDP_ENDIAN__\n__OS400__\n__OpenBSD__\n__PA7100__\n__PA8000__\n__PATHCC__\n__PDP_ENDIAN\n__PGI\n__PGIC_MINOR__\n__PGIC_PATCHLEVEL__\n__PGIC__\n__PIC__\n__PIE__\n__POINTER_WIDTH__\n__POWERPC__\n__PPCBROADWAY__\n__PPCGECKO__\n__PRAGMA_REDEFINE_EXTNAME\n__PTRDIFF_MAX__\n__PTRDIFF_TYPE__\n__PTRDIFF_WIDTH__\n__QNXNTO__\n__QNX__\n__QQ_FBIT__\n__QQ_IBIT__\n__REGISTER_PREFIX__\n__RISC2_0__\n__SACCUM_EPSILON__\n__SACCUM_FBIT__\n__SACCUM_IBIT__\n__SACCUM_MAX__\n__SACCUM_MIN__\n__SA_FBIT__\n__SA_IBIT__\n__SCHAR_MAX__\n__SEG_FS\n__SEG_GS\n__SFRACT_EPSILON__\n__SFRACT_FBIT__\n__SFRACT_IBIT__\n__SFRACT_MAX__\n__SFRACT_MIN__\n__SGI_STL\n__SGI_STL_PORT\n__SH3__\n__SH4__\n__SH5__\n__SHRT_MAX__\n__SIG_ATOMIC_MAX__\n__SIG_ATOMIC_MIN__\n__SIG_ATOMIC_TYPE__\n__SIG_ATOMIC_WIDTH__\n__SIZEOF_DOUBLE__\n__SIZEOF_FLOAT128__\n__SIZEOF_FLOAT80__\n__SIZEOF_FLOAT__\n__SIZEOF_INT128__\n__SIZEOF_INT__\n__SIZEOF_LONG_DOUBLE__\n__SIZEOF_LONG_LONG__\n__SIZEOF_LONG__\n__SIZEOF_POINTER__\n__SIZEOF_PTRDIFF_T__\n__SIZEOF_SHORT__\n__SIZEOF_SIZE_T__\n__SIZEOF_WCHAR_T__\n__SIZEOF_WINT_T__\n__SIZE_MAX__\n__SIZE_TYPE__\n__SIZE_WIDTH__\n__SQ_FBIT__\n__SQ_IBIT__\n__SSE2_MATH__\n__SSE2__\n__SSE3__\n__SSE4A__\n__SSE4_1__\n__SSE4_2__\n__SSE_MATH__\n__SSE__\n__SSP_STRONG__\n__SSP__\n__SSSE3__\n__STDCPP_DEFAULT_NEW_ALIGNMENT__\n__STDCPP_STRICT_POINTER_SAFETY__\n__STDCPP_THREADS__\n__STDC_HOSTED__\n__STDC_IEC_559_COMPLEX__\n__STDC_IEC_559__\n__STDC_ISO_10646__\n__STDC_MB_MIGHT_NEQ_WC__\n__STDC_NO_THREADS__\n__STDC_UTF_16__\n__STDC_UTF_32__\n__STDC_VERSION__\n__STDC__\n__STD_RWCOMPILER_H__\n__STL_CONFIG_H\n__SUNPRO_C\n__SUNPRO_CC\n__SVR4\n__SYSC_ZARCH__\n__SYSC__\n__TARGET_ARCH_ARM\n__TARGET_ARCH_THUMB\n__TARGET_LIB__\n__TA_FBIT__\n__TA_IBIT__\n__THUMBEB__\n__THUMBEL__\n__THUMB_INTERWORK__\n__THW_370__\n__THW_INTEL__\n__THW_RS6000\n__TOS_AIX__\n__TOS_WIN__\n__TQ_FBIT__\n__TQ_IBIT__\n__TenDRA__\n__UACCUM_EPSILON__\n__UACCUM_FBIT__\n__UACCUM_IBIT__\n__UACCUM_MAX__\n__UACCUM_MIN__\n__UCLIBC__\n__UDA_FBIT__\n__UDA_IBIT__\n__UDQ_FBIT__\n__UDQ_IBIT__\n__UFRACT_EPSILON__\n__UFRACT_FBIT__\n__UFRACT_IBIT__\n__UFRACT_MAX__\n__UFRACT_MIN__\n__UHA_FBIT__\n__UHA_IBIT__\n__UHQ_FBIT__\n__UHQ_IBIT__\n__UINT16_C\n__UINT16_MAX__\n__UINT16_TYPE__\n__UINT32_C\n__UINT32_MAX__\n__UINT32_TYPE__\n__UINT64_C\n__UINT64_MAX__\n__UINT64_TYPE__\n__UINT8_C\n__UINT8_MAX__\n__UINT8_TYPE__\n__UINTMAX_C\n__UINTMAX_MAX__\n__UINTMAX_TYPE__\n__UINTPTR_MAX__\n__UINTPTR_TYPE__\n__UINT_FAST16_MAX__\n__UINT_FAST16_TYPE__\n__UINT_FAST32_MAX__\n__UINT_FAST32_TYPE__\n__UINT_FAST64_MAX__\n__UINT_FAST64_TYPE__\n__UINT_FAST8_MAX__\n__UINT_FAST8_TYPE__\n__UINT_LEAST16_MAX__\n__UINT_LEAST16_TYPE__\n__UINT_LEAST32_MAX__\n__UINT_LEAST32_TYPE__\n__UINT_LEAST64_MAX__\n__UINT_LEAST64_TYPE__\n__UINT_LEAST8_MAX__\n__UINT_LEAST8_TYPE__\n__ULACCUM_EPSILON__\n__ULACCUM_FBIT__\n__ULACCUM_IBIT__\n__ULACCUM_MAX__\n__ULACCUM_MIN__\n__ULFRACT_EPSILON__\n__ULFRACT_FBIT__\n__ULFRACT_IBIT__\n__ULFRACT_MAX__\n__ULFRACT_MIN__\n__ULLACCUM_EPSILON__\n__ULLACCUM_FBIT__\n__ULLACCUM_IBIT__\n__ULLACCUM_MAX__\n__ULLACCUM_MIN__\n__ULLFRACT_EPSILON__\n__ULLFRACT_FBIT__\n__ULLFRACT_IBIT__\n__ULLFRACT_MAX__\n__ULLFRACT_MIN__\n__UQQ_FBIT__\n__UQQ_IBIT__\n__USACCUM_EPSILON__\n__USACCUM_FBIT__\n__USACCUM_IBIT__\n__USACCUM_MAX__\n__USACCUM_MIN__\n__USA_FBIT__\n__USA_IBIT__\n__USER_LABEL_PREFIX__\n__USFRACT_EPSILON__\n__USFRACT_FBIT__\n__USFRACT_IBIT__\n__USFRACT_MAX__\n__USFRACT_MIN__\n__USING_SJLJ_EXCEPTIONS__\n__USQ_FBIT__\n__USQ_IBIT__\n__UTA_FBIT__\n__UTA_IBIT__\n__UTQ_FBIT__\n__UTQ_IBIT__\n__VECTOR4DOUBLE__\n__VEC__\n__VERSION__\n__VFP_FP__\n__VMS\n__VMS_VER\n__VSX__\n__WATCOMC__\n__WCHAR_MAX__\n__WCHAR_MIN__\n__WCHAR_TYPE__\n__WCHAR_UNSIGNED__\n__WCHAR_WIDTH__\n__WIN32__\n__WINDOWS__\n__WINT_MAX__\n__WINT_MIN__\n__WINT_TYPE__\n__WINT_WIDTH__\n__XOP__\n__aarch64__\n__alpha\n__alpha__\n__alpha_ev4__\n__alpha_ev5__\n__alpha_ev6__\n__amd64\n__amd64__\n__amigaos__\n__apple_build_version__\n__arm\n__arm64\n__arm64__\n__arm__\n__bfin__\n__block\n__bsdi__\n__clang__\n__clang_major__\n__clang_minor__\n__clang_patchlevel__\n__clang_version__\n__code_model_small__\n__convex__\n__convex_c1__\n__convex_c2__\n__convex_c32__\n__convex_c34__\n__convex_c38__\n__core2\n__core2__\n__cplusplus\n__cplusplus_cli\n__cplusplus_winrt\n__cpp_aggregate_nsdmi\n__cpp_alias_templates\n__cpp_attributes\n__cpp_binary_literals\n__cpp_constexpr\n__cpp_decltype\n__cpp_decltype_auto\n__cpp_delegating_constructors\n__cpp_digit_separators\n__cpp_exceptions\n__cpp_generic_lambdas\n__cpp_hex_float\n__cpp_inheriting_constructors\n__cpp_init_captures\n__cpp_initializer_lists\n__cpp_lambdas\n__cpp_nsdmi\n__cpp_range_based_for\n__cpp_raw_strings\n__cpp_ref_qualifiers\n__cpp_return_type_deduction\n__cpp_rtti\n__cpp_runtime_arrays\n__cpp_rvalue_reference\n__cpp_sized_deallocation\n__cpp_static_assert\n__cpp_unicode_characters\n__cpp_unicode_literals\n__cpp_user_defined_literals\n__cpp_variable_templates\n__cpp_variadic_templates\n__embedded_cplusplus\n__ghs\n__ghs__\n__gnu_linux__\n__hppa\n__hppa__\n__hpux\n__i386\n__i386__\n__i486__\n__i586__\n__i686__\n__ia64\n__ia64__\n__itanium__\n__k8\n__k8__\n__linux\n__linux__\n__llvm__\n__m68k__\n__mc68000\n__mc68000__\n__mc68010\n__mc68010__\n__mc68020\n__mc68020__\n__mc68030\n__mc68030__\n__mc68040\n__mc68040__\n__mc68060\n__mc68060__\n__mips\n__mips__\n__nocona\n__nocona__\n__pic__\n__pie__\n__powerpc\n__powerpc__\n__ppc601__\n__ppc603__\n__ppc604__\n__ppc__\n__private_extern__\n__s390__\n__s390x__\n__sgi\n__sh1__\n__sh2__\n__sh3__\n__sh__\n__sparc\n__sparc__\n__sparcv8\n__sparcv9\n__strong\n__sun\n__svr4__\n__sysv__\n__thumb2__\n__thumb__\n__tune_core2__\n__tune_nocona__\n__unix\n__unix__\n__unsafe_unretained\n__weak\n__x86_64\n__x86_64__\n__xlC__\n__xlc__\n_hpux\n"
  },
  {
    "path": "scripts/try-copy-license.cmake",
    "content": "# Copyright (c) 2015 Aaditya Kalsi\n# Copyright (c) 2017 Ruslan Baratov\n# All rights reserved.\n\ncmake_minimum_required(VERSION 3.0)\n\nstring(COMPARE EQUAL \"${srcdir}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"'srcdir' should not be empty\")\nendif()\n\nstring(COMPARE EQUAL \"${dstdir}\" \"\" is_empty)\nif(is_empty)\n  message(FATAL_ERROR \"'dstdir' should not be empty\")\nendif()\n\nset(licenses \"${HUNTER_INSTALL_LICENSE_FILES}\")\nstring(COMPARE NOTEQUAL \"${licenses}\" \"\" explicit_licenses)\n\nfile(MAKE_DIRECTORY \"${dstdir}\")\nif(NOT EXISTS \"${dstdir}\")\n  message(FATAL_ERROR \"Can't create directory: '${dstdir}'\")\nendif()\nif(NOT IS_DIRECTORY \"${dstdir}\")\n  message(FATAL_ERROR \"Is not a directory: '${dstdir}'\")\nendif()\n\n# Use set explicit license files for the package\n# Testing variants:\n# * Eigen \"HUNTER_INSTALL_LICENSE_FILES=COPYING.MPL2\" (good)\n# * Eigen \"HUNTER_INSTALL_LICENSE_FILES=COPYING.BSD;COPYING.GPL;COPYING.LGPL;COPYING.MINPACK;COPYING.MPL2\" (good)\n# * Eigen \"HUNTER_INSTALL_LICENSE_FILES=COPYING.BSD;COPYING.GPL;COPYING.LGPL;COPYING.XXX;COPYING.MPL2\" (bad)\n# * Eigen no HUNTER_INSTALL_LICENSE_FILES (bad, no default license)\nif(explicit_licenses)\n  foreach(x ${licenses})\n    if(NOT EXISTS \"${srcdir}/${x}\")\n      message(FATAL_ERROR \"File not found: '${srcdir}/${x}'\")\n    endif()\n    file(COPY \"${srcdir}/${x}\" DESTINATION \"${dstdir}\")\n  endforeach()\n  return()\nendif()\n\n# Try standard names\nforeach(x \"LICENSE\" \"LICENSE.txt\" \"COPYING\" \"COPYING.txt\" \"license\" \"license.txt\" \"copying\" \"copying.txt\")\n  if(EXISTS \"${srcdir}/${x}\")\n    file(COPY \"${srcdir}/${x}\" DESTINATION \"${dstdir}\")\n    return()\n  endif()\nendforeach()\n\n# If no standard name found try to glob LICENSE*\n# Testing variants:\n# * Boost\nfile(GLOB filelist \"${srcdir}/LICENSE*\")\nforeach(x ${filelist})\n  if(NOT IS_DIRECTORY \"${x}\")\n    file(COPY \"${x}\" DESTINATION \"${dstdir}\")\n  endif()\nendforeach()\n"
  },
  {
    "path": "scripts/upload-cache-to-github.py",
    "content": "#!/usr/bin/env python3\nfrom __future__ import print_function\n\nimport argparse\nimport hashlib\nimport json\nimport os\nimport requests\nimport sys\nimport time\n\nif os.getenv('HUNTER_GIT_EXECUTABLE'):\n  os.environ[\"GIT_PYTHON_GIT_EXECUTABLE\"] = os.getenv('HUNTER_GIT_EXECUTABLE')\n\ntry:\n  import git\nexcept ImportError as exc:\n  print(\"Import failed with error: {}\".format(exc))\n  print(\"Possible fixes:\")\n  print(\" * Install gitpython module: 'pip install gitpython'\")\n  print(\" * Set environment variable HUNTER_GIT_EXECUTABLE\")\n  sys.exit(1)\n\nclass Error(Exception):\n  pass\n\ndef sleep_time(attempt):\n  if attempt <= 0:\n    raise Exception('Unexpected')\n  if attempt == 1:\n    return 0\n  if attempt == 2:\n    return 15\n  if attempt == 3:\n    return 60\n  if attempt == 4:\n    return 90\n  if attempt == 5:\n    return 300\n  return 1200\n\ndef retry(func_in):\n  def func_out(*args, **kwargs):\n    retry_max = 10\n    i = 0\n    while True:\n      i = i + 1\n      try:\n        return func_in(*args, **kwargs)\n      except Error as err:\n        # Treat Errors as fatal and do not retry.\n        # Also explicitly flush message to avoid \"no output\" issue on some CIs.\n        print('Error:\\n  {}'.format(err))\n        sys.stdout.flush()\n        raise err\n      except Exception as exc:\n        if i > retry_max:\n          raise exc\n        print('Operation failed. Exception:\\n  {}'.format(exc))\n        sec = sleep_time(i)\n        print('Retry #{} (of {}) after {} seconds'.format(i, retry_max, sec))\n        sys.stdout.flush()\n        time.sleep(sec)\n  return func_out\n\nclass Github:\n  def __init__(self, username, password, repo_owner, repo):\n    self.repo_owner = repo_owner\n    self.repo = repo\n    self.username = username\n    self.password = password\n    self.auth = requests.auth.HTTPBasicAuth(username, password)\n    self.simple_request()\n\n  @retry\n  def simple_request(self):\n    print('Processing simple request')\n    r = requests.get('https://api.github.com', auth=self.auth)\n    if not r.ok:\n      sys.exit('Simple request fails. Check your password.')\n\n    limit = int(r.headers['X-RateLimit-Remaining'])\n    print('GitHub Limit: {}'.format(limit))\n    if limit == 0:\n      raise Exception('GitHub limit is 0')\n    print('Simple request pass')\n\n  @retry\n  def get_release_by_tag(self, tagname):\n    print('Get release-id by tag `{}`'.format(tagname))\n    # https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name\n    # GET /repos/:owner/:repo/releases/tags/:tag\n\n    url = 'https://api.github.com/repos/{}/{}/releases/tags/{}'.format(\n        self.repo_owner,\n        self.repo,\n        tagname\n    )\n\n    r = requests.get(url, auth=self.auth)\n    if r.status_code == 404:\n        # Create release if not exists\n        # https://developer.github.com/v3/repos/releases/#create-a-release\n        # POST /repos/:owner/:repo/releases\n\n        post_url = 'https://api.github.com/repos/{}/{}/releases'.format(\n            self.repo_owner,\n            self.repo,\n        )\n        tag_data = \"{\" + '\"tag_name\": \"{}\"'.format(tagname) + \"}\"\n        r = requests.post(post_url, data=tag_data, auth=self.auth)\n        repo_name = \"https://github.com/{}/{}\".format(\n            self.repo_owner, self.repo\n        )\n        if r.status_code == 404:\n            raise Error(\n                \"Repository not found '{}' or user '{}' has no access to it\".\n                    format(repo_name, self.username)\n            )\n        if r.status_code == 422:\n            raise Error(\n                \"Please create at least one file in repository '{}'\".\n                    format(repo_name)\n            )\n        if not r.status_code == 201:\n            raise Error(\"Unexpected status code: {}\".format(r.status_code))\n        if not r.ok:\n            raise Error(\"Can't create release tag {}\".format(tagname))\n        r = requests.get(url, auth=self.auth)\n\n    if not r.ok:\n        raise Exception(\n            'Get release id failed. Status code: {}. Requested url: {}'.format(\n                r.status_code, url))\n\n    release_id = r.json()['id']\n    upload_url = r.json()['upload_url']\n    uri_template_vars = '{?name,label}'\n    if uri_template_vars not in upload_url:\n        raise Exception('Unsupported upload URI template: {}'.format(upload_url))\n    upload_url = upload_url.replace(uri_template_vars, '?name={}')\n    print('Release id: {}'.format(release_id))\n    print('Upload URL: {}'.format(upload_url))\n    return release_id, upload_url\n\n  @retry\n  def find_asset_id_by_name(self, release_id, name):\n    # https://developer.github.com/v3/repos/releases/#list-assets-for-a-release\n    # GET /repos/:owner/:repo/releases/:id/assets\n\n    page_number = 1\n    keep_searching = True\n\n    while keep_searching:\n      url = 'https://api.github.com/repos/{}/{}/releases/{}/assets?page={}'.format(\n          self.repo_owner,\n          self.repo,\n          release_id,\n          page_number\n      )\n\n      print('Requesting URL: {}'.format(url))\n      r = requests.get(url, auth=self.auth)\n      if not r.ok:\n        raise Exception('Getting list of assets failed. Requested url: {}'.format(url))\n\n      json = r.json()\n\n      for x in json:\n        if name == x['name']:\n          return x['id']\n\n      if not json:\n        keep_searching = False\n\n      page_number = page_number + 1\n\n    return None\n\n  @retry\n  def delete_asset_by_id(self, asset_id, asset_name):\n    # https://developer.github.com/v3/repos/releases/#delete-a-release-asset\n    # DELETE /repos/:owner/:repo/releases/assets/:id\n\n    url = 'https://api.github.com/repos/{}/{}/releases/assets/{}'.format(\n        self.repo_owner,\n        self.repo,\n        asset_id\n    )\n\n    r = requests.delete(url, auth=self.auth)\n    if r.status_code == 204:\n      print('Asset removed: {}'.format(asset_name))\n    else:\n      raise Exception('Deletion of asset failed: {}'.format(asset_name))\n\n  def delete_asset_if_exists(self, release_id, asset_name):\n    asset_id = self.find_asset_id_by_name(release_id, asset_name)\n    if not asset_id:\n      print('Asset not exists: {}'.format(asset_name))\n      return\n    self.delete_asset_by_id(asset_id, asset_name)\n\n  def upload_bzip_once(self, url, local_path):\n    headers = {'Content-Type': 'application/x-bzip2'}\n    file_to_upload = open(local_path, 'rb')\n    r = requests.post(url, data=file_to_upload, headers=headers, auth=self.auth)\n    if not r.ok:\n      raise Exception('Upload of file failed')\n\n  @retry\n  def upload_bzip(self, url, local_path, release_id, asset_name):\n    print('Uploading:\\n  {}\\n  -> {}'.format(local_path, url))\n    try:\n      self.upload_bzip_once(url, local_path)\n    except Exception as exc:\n      print('Exception catched while uploading, removing asset...')\n      self.delete_asset_if_exists(release_id, asset_name)\n      raise exc\n\n  def upload_raw_file(self, local_path):\n    asset_name = hashlib.sha1(open(local_path, 'rb').read()).hexdigest()\n\n    tagname = 'cache-{}'.format(asset_name[0:7])\n    asset_name = asset_name + '.tar.bz2'\n\n    release_id, upload_url = self.get_release_by_tag(tagname)\n\n    # https://developer.github.com/v3/repos/releases/#upload-a-release-asset\n    # POST to upload_url received in the release description\n    # in get_release_by_tag()\n\n    url = upload_url.format(asset_name)\n    self.upload_bzip(url, local_path, release_id, asset_name)\n\nclass CacheEntry:\n  def __init__(self, cache_done_path, cache_dir):\n    self.cache_dir = cache_dir\n    self.cache_raw = os.path.join(self.cache_dir, 'raw')\n    self.cache_done_path = cache_done_path\n    if not os.path.exists(cache_done_path):\n      raise Exception('File not exists: {}'.format(cache_done_path))\n    self.cache_done_dir = os.path.dirname(self.cache_done_path)\n    self.from_server = os.path.join(self.cache_done_dir, 'from.server')\n    self.cache_sha1 = os.path.join(self.cache_done_dir, 'cache.sha1')\n\n  def entry_from_server(self):\n    return os.path.exists(self.from_server)\n\n  def upload_raw(self, github):\n    sha1 = open(self.cache_sha1, 'r').read()\n    if sha1 == '':\n      sys.exit('File with no content: {}'.format(self.cache_sha1))\n    raw = os.path.join(self.cache_raw, sha1 + '.tar.bz2')\n    if os.path.exists(raw):\n      github.upload_raw_file(raw)\n\n    # else:\n    # FIXME (old GitHub API upload): https://travis-ci.org/ingenue/hunter/jobs/347888167\n    # New Git-based upload: 'from.server' not present for old cache\n\n  def touch_from_server(self):\n    open(self.from_server, 'w')\n\nclass Cache:\n  def __init__(self, cache_dir):\n    self.cache_meta = os.path.join(cache_dir, 'meta')\n    self.repo = git.Repo.init(self.cache_meta)\n\n    self.entries = self.create_entries(cache_dir)\n    self.remove_entries_from_server()\n\n  def create_entries(self, cache_dir):\n    print('Searching for CACHE.DONE files in directory:\\n  {}\\n'.format(cache_dir))\n\n    entries = []\n    for x in self.repo.untracked_files:\n      if x.endswith('CACHE.DONE'):\n        entries.append(CacheEntry(os.path.join(self.cache_meta, x), cache_dir))\n    print('Found {} files'.format(len(entries)))\n    return entries\n\n  def remove_entries_from_server(self):\n    new_entries = []\n    for i in self.entries:\n      if not i.entry_from_server():\n        new_entries.append(i)\n    self.entries = new_entries\n\n  def upload_raw(self, github):\n    for i in self.entries:\n      i.upload_raw(github)\n\n  def make_commit_message(self):\n    message = 'Uploading cache info\\n\\n'\n\n    env_list = []\n    job_url = ''\n\n    if os.getenv('TRAVIS') == 'true':\n      # * https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables\n      message += 'Travis:\\n'\n      job_url = 'https://travis-ci.org/{}/jobs/{}'.format(\n          os.getenv('TRAVIS_REPO_SLUG'),\n          os.getenv('TRAVIS_JOB_ID')\n      )\n\n      env_list += [\n          'TRAVIS_BRANCH',\n          'TRAVIS_BUILD_ID',\n          'TRAVIS_BUILD_NUMBER',\n          'TRAVIS_JOB_ID',\n          'TRAVIS_JOB_NUMBER',\n          'TRAVIS_OS_NAME',\n          'TRAVIS_REPO_SLUG'\n      ]\n\n    if os.getenv('APPVEYOR') == 'True':\n      # * http://www.appveyor.com/docs/environment-variables\n      message += 'AppVeyor:\\n'\n      job_url = 'https://ci.appveyor.com/project/{}/{}/build/{}/job/{}'.format(\n          os.getenv('APPVEYOR_ACCOUNT_NAME'),\n          os.getenv('APPVEYOR_PROJECT_SLUG'),\n          os.getenv('APPVEYOR_BUILD_VERSION'),\n          os.getenv('APPVEYOR_JOB_ID')\n      )\n      env_list += [\n          'APPVEYOR_ACCOUNT_NAME',\n          'APPVEYOR_PROJECT_ID',\n          'APPVEYOR_PROJECT_NAME',\n          'APPVEYOR_PROJECT_SLUG',\n          'APPVEYOR_BUILD_ID',\n          'APPVEYOR_BUILD_NUMBER',\n          'APPVEYOR_BUILD_VERSION',\n          'APPVEYOR_JOB_ID',\n          'APPVEYOR_JOB_NAME',\n          'APPVEYOR_REPO_BRANCH'\n      ]\n\n    # Store some info about build\n    for env_name in env_list:\n      env_value = os.getenv(env_name)\n      if env_value:\n        message += '  {}: {}\\n'.format(env_name, env_value)\n\n    if job_url:\n      message += '\\n  Job URL: {}\\n'.format(job_url)\n\n    return message\n\n  def try_to_push(self, main_remote, main_remote_url_pull, github):\n    try:\n      fetch_result = main_remote.pull(\n          allow_unrelated_histories=True,\n          strategy='recursive',\n          strategy_option='ours',\n          rebase=True,\n          depth=1\n      )\n      for x in fetch_result:\n        if x.flags & x.REJECTED:\n          print('Pull rejected')\n          return False\n        if x.flags & x.ERROR:\n          print('Pull error')\n          return False\n    except Exception as exc:\n      print(\"Pull failed: {}\".format(exc))\n      return False\n\n    try:\n      main_remote.set_url(\n          'https://{}:{}@github.com/{}/{}'.format(\n              github.username,\n              github.password,\n              github.repo_owner,\n              github.repo\n          )\n      )\n      push_result = main_remote.push()\n      main_remote.set_url(main_remote_url_pull)\n      for x in push_result:\n        if x.flags & x.ERROR:\n          print('Push error')\n          return False\n        if x.flags & x.REJECTED:\n          print('Push rejected')\n          return False\n        if x.flags & x.REMOTE_FAILURE:\n          print('Push remote failure')\n          return False\n        if x.flags & x.REMOTE_REJECTED:\n          print('Push remote rejected')\n          return False\n    except:\n      # No exceptions expected, exit to avoid leakage of token\n      sys.exit('Unexpected exception')\n\n    return True\n\n  def upload_meta(self, github, cache_dir):\n    config = self.repo.config_writer()\n    config.set_value(\n        \"user\",\n        \"email\",\n        \"{}@users.noreply.github.com\".format(github.username)\n    )\n    config.set_value(\"user\", \"name\", github.username)\n    config.release()\n\n    if self.repo.is_dirty(untracked_files=True):\n      print('Adding untracked files:')\n      add_list = []\n\n      for x in self.repo.untracked_files:\n        to_add = False\n        if x.endswith('toolchain.info'):\n          to_add = True\n        elif x.endswith('args.cmake'):\n          to_add = True\n        elif x.endswith('types.info'):\n          to_add = True\n        elif x.endswith('internal_deps.id'):\n          to_add = True\n        elif x.endswith('basic-deps.info'):\n          to_add = True\n        elif x.endswith('basic-deps.DONE'):\n          to_add = True\n        elif x.endswith('cache.sha1'):\n          to_add = True\n        elif x.endswith('deps.info'):\n          to_add = True\n        elif x.endswith('CACHE.DONE'):\n          to_add = True\n        elif x.endswith('SHA1'):\n          to_add = True\n\n        if to_add:\n          print(' * {}'.format(x))\n          add_list.append(x)\n\n      sys.stdout.flush()\n\n      self.repo.index.add(add_list)\n      self.repo.index.commit(self.make_commit_message())\n\n    main_branch_found = False\n    for branch in self.repo.branches:\n      if branch.name == 'master':\n        main_branch_found = True\n\n    if not main_branch_found:\n      self.repo.git.branch('master')\n\n    main_remote_found = False\n    for remote in self.repo.remotes:\n      if remote.name == 'origin':\n        main_remote_found = True\n        main_remote = remote\n\n    main_remote_url_pull = 'https://github.com/{}/{}'.format(\n        github.repo_owner, github.repo\n    )\n\n    if not main_remote_found:\n      main_remote = self.repo.create_remote('origin', main_remote_url_pull)\n\n    retry_max = 10\n\n    fetch_ok = False\n\n    for i in range(1, retry_max):\n      try:\n        if fetch_ok:\n          break\n        print('Fetch remote (attempt #{})'.format(i))\n        sys.stdout.flush()\n\n        main_remote.fetch(depth=1)\n        fetch_ok = True\n      except Exception as exc:\n        print('Exception {}'.format(exc))\n\n    if not fetch_ok:\n      sys.exit('Fetch failed')\n\n    self.repo.heads.master.set_tracking_branch(main_remote.refs.master)\n\n    success = False\n\n    for i in range(1, retry_max):\n      print(\"Attempt #{}\".format(i))\n      success = self.try_to_push(main_remote, main_remote_url_pull, github)\n      if success:\n        break\n      sec = sleep_time(i)\n      print('Retry #{} (of {}) after {} seconds'.format(i, retry_max, sec))\n      sys.stdout.flush()\n      time.sleep(sec)\n\n    if success:\n      print(\"Done\")\n    else:\n      sys.exit(\"Can't push\")\n\n  def touch_from_server(self):\n    for i in self.entries:\n      i.touch_from_server()\n\nparser = argparse.ArgumentParser(\n    description='Script for uploading Hunter cache files to GitHub'\n)\n\nparser.add_argument(\n    '--username',\n    required=True,\n    help='Username'\n)\n\nparser.add_argument(\n    '--password',\n    required=True,\n    help='Password'\n)\n\nparser.add_argument(\n    '--repo-owner',\n    required=True,\n    help='Repository owner'\n)\n\nparser.add_argument(\n    '--repo',\n    required=True,\n    help='Repository name'\n)\n\nparser.add_argument(\n    '--cache-dir',\n    required=True,\n    help='Hunter cache directory, e.g. /home/user/.hunter/_Base/Cache'\n)\n\nargs = parser.parse_args()\n\ncache_dir = os.path.normpath(args.cache_dir)\n\n# Some tests don't produce cache for some toolchains:\n# * https://travis-ci.org/ingenue/hunter/jobs/185550289\nif not os.path.exists(cache_dir):\n  print(\"*** WARNING *** Cache directory '{}' not found, skipping...\".format(cache_dir))\n  sys.exit()\n\nif not os.path.isdir(cache_dir):\n  raise Exception('Not a directory: {}'.format(cache_dir))\n\nif os.path.split(cache_dir)[1] != 'Cache':\n  raise Exception('Cache directory path should ends with Cache: {}'.format(cache_dir))\n\ncache = Cache(cache_dir)\n\npassword = args.password\n\nif password == '' or password is None:\n  raise Exception('No password provided')\n\ngithub = Github(\n    username = args.username,\n    password = password,\n    repo_owner = args.repo_owner,\n    repo = args.repo\n)\n\ncache.upload_raw(github)\n\ncache.upload_meta(github, cache_dir)\nprint('Touch from.server files')\ncache.touch_from_server()\n"
  },
  {
    "path": "utils/git-hooks/commit-msg",
    "content": "#!/usr/bin/env python\n#!/usr/bin/env python\nfrom difflib import unified_diff as differ\nimport os\nfrom subprocess import check_output as call\nimport sys\nimport shutil\n\n\ndef read(filepath):\n    mode = \"b\" if sys.platform.startswith(\"win\") else \"\"\n    data = \"\"\n    with open(filepath, \"rU\" + mode) as fd:\n        data = fd.read()\n    return data\n\n\ndef get_current_revision():\n    cmd = \"git rev-parse --verify HEAD\".split(\" \")\n    gitrev = \"\".join(r.strip() for r in call(cmd).split(\"\\n\") if r.strip())\n    return gitrev\n\n\ndef get_commit_filename():\n    commit_filename = sys.argv[1]\n    return commit_filename\n\n\ndef get_project_path():\n    cmd = \"git rev-parse --show-toplevel\".split(\" \")\n    project_path = \"\".join(p.strip()\n                           for p in call(cmd).split(\"\\n\")\n                           if p.strip())\n    return project_path\n\n\ndef get_hooks_path():\n    gitpath = get_project_path()\n    hookspath = os.path.join(gitpath, 'utils', 'git-hooks')\n    if not hookspath:\n        hookspath = os.getcwd()\n    return hookspath\n\n\ndef get_subhooks(hookspath, gitpath, fname):\n    sub_hooks = []\n    for root, folders, files in os.walk(hookspath):\n        for filename in files:\n            hookpath = os.path.join(gitpath, root, filename)\n            if filename.startswith(fname) and filename != fname:\n                sub_hooks.append(hookpath)\n    return sub_hooks\n\n\ndef check_for_update():\n    fname = os.path.basename(__file__)\n    gitpath = get_project_path()\n    old_path = os.path.join(gitpath, '.git', 'hooks', fname)\n    new_path = os.path.join(gitpath, 'utils', 'git-hooks', fname)\n    old_data = read(old_path)\n    new_data = read(new_path)\n    diff = list(differ(old_data.splitlines(),\n                       new_data.splitlines(),\n                       old_path, new_path))\n    changed = '\\n'.join(diff)\n    if changed:\n        shutil.copyfile(new_path, old_path)\n        shutil.copymode(new_path, old_path)\n        shutil.copystat(new_path, old_path)\n        print >> sys.stderr, \"%s updated.  Please re-run.\" % fname\n        sys.exit(1)\n\n\ndef run_sub_hooks():\n    fname = os.path.basename(__file__)\n    gitrev = get_current_revision()\n    git_commit_filename = get_commit_filename()\n    gitpath = get_project_path()\n    hookspath = get_hooks_path()\n    sub_hooks = get_subhooks(hookspath, gitpath, fname)\n    for hookpath in sub_hooks:\n        fpath = os.path.join(gitpath, git_commit_filename)\n        cmd = [hookpath, fpath]\n        output = call(cmd)\n        if output:\n            print output\n\n\nif __name__ == \"__main__\":\n    check_for_update()\n    run_sub_hooks()\n"
  },
  {
    "path": "utils/git-hooks/commit-msg_check-spelling",
    "content": "#!/bin/bash\nASPELL=$(which aspell)\nif [ $? -ne 0 ]; then\n    echo \"Aspell not installed - unable to check spelling\" >&2\n    exit 0\nfi\n\nAWK=$(which awk)\nif [ $? -ne 0 ]; then\n    echo \"Awk not installed - unable to filter spelling errors\" >&2\n    WORDS=$($ASPELL list < \"$1\")\nelse\n    WORDS=$($ASPELL list < \"$1\" | $AWK '!_[$0]++')\nfi\n\nif [ -n \"$WORDS\" ]; then\n    echo \"Possible spelling errors found in commit message: \" $WORDS >&2\n    echo \"To fix, use:  git commit --amend\"\nfi\n\nexit 0"
  },
  {
    "path": "utils/git-hooks/cpplint/__init__.py",
    "content": ""
  },
  {
    "path": "utils/git-hooks/cpplint/cpplint.py",
    "content": "#!/usr/bin/env python\n#\n# Copyright (c) 2009 Google Inc. All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are\n# met:\n#\n#    * Redistributions of source code must retain the above copyright\n# notice, this list of conditions and the following disclaimer.\n#    * Redistributions in binary form must reproduce the above\n# copyright notice, this list of conditions and the following disclaimer\n# in the documentation and/or other materials provided with the\n# distribution.\n#    * Neither the name of Google Inc. nor the names of its\n# contributors may be used to endorse or promote products derived from\n# this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n# Here are some issues that I've had people identify in my code during reviews,\n# that I think are possible to flag automatically in a lint tool.  If these were\n# caught by lint, it would save time both for myself and that of my reviewers.\n# Most likely, some of these are beyond the scope of the current lint framework,\n# but I think it is valuable to retain these wish-list items even if they cannot\n# be immediately implemented.\n#\n#  Suggestions\n#  -----------\n#  - Check for no 'explicit' for multi-arg ctor\n#  - Check for boolean assign RHS in parens\n#  - Check for ctor initializer-list colon position and spacing\n#  - Check that if there's a ctor, there should be a dtor\n#  - Check accessors that return non-pointer member variables are\n#    declared const\n#  - Check accessors that return non-const pointer member vars are\n#    *not* declared const\n#  - Check for using public includes for testing\n#  - Check for spaces between brackets in one-line inline method\n#  - Check for no assert()\n#  - Check for spaces surrounding operators\n#  - Check for 0 in pointer context (should be NULL)\n#  - Check for 0 in char context (should be '\\0')\n#  - Check for camel-case method name conventions for methods\n#    that are not simple inline getters and setters\n#  - Check that base classes have virtual destructors\n#    put \"  // namespace\" after } that closes a namespace, with\n#    namespace's name after 'namespace' if it is named.\n#  - Do not indent namespace contents\n#  - Avoid inlining non-trivial constructors in header files\n#    include base/basictypes.h if DISALLOW_EVIL_CONSTRUCTORS is used\n#  - Check for old-school (void) cast for call-sites of functions\n#    ignored return value\n#  - Check gUnit usage of anonymous namespace\n#  - Check for class declaration order (typedefs, consts, enums,\n#    ctor(s?), dtor, friend declarations, methods, member vars)\n#\n\n\"\"\"Does google-lint on c++ files.\n\nThe goal of this script is to identify places in the code that *may*\nbe in non-compliance with google style.  It does not attempt to fix\nup these problems -- the point is to educate.  It does also not\nattempt to find all problems, or to ensure that everything it does\nfind is legitimately a problem.\n\nIn particular, we can get very confused by /* and // inside strings!\nWe do a small hack, which is to ignore //'s with \"'s after them on the\nsame line, but it is far from perfect (in either direction).\n\"\"\"\n\nimport codecs\nimport getopt\nimport math  # for log\nimport os\nimport re\nimport sre_compile\nimport string\nimport sys\nimport unicodedata\n\nEXTENSIONS = ['c', 'cc', 'cpp', 'cxx', 'c++',\n              'h', 'hpp', 'hxx', 'h++']\n\n_USAGE = \"\"\"\nSyntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]\n                   [--counting=total|toplevel|detailed]\n        <file> [file] ...\n\n  The style guidelines this tries to follow are those in\n    http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml\n\n  Every problem is given a confidence score from 1-5, with 5 meaning we are\n  certain of the problem, and 1 meaning it could be a legitimate construct.\n  This will miss some errors, and is not a substitute for a code review.\n\n  To suppress false-positive errors of a certain category, add a\n  'NOLINT(category)' comment to the line.  NOLINT or NOLINT(*)\n  suppresses errors of all categories on that line.\n\n  The files passed in will be linted; at least one file must be provided.\n  Linted extensions are %s.  Other file types will be ignored.\n\n  Flags:\n\n    output=vs7\n      By default, the output is formatted to ease emacs parsing.  Visual Studio\n      compatible output (vs7) may also be used.  Other formats are unsupported.\n\n    verbose=#\n      Specify a number 0-5 to restrict errors to certain verbosity levels.\n\n    filter=-x,+y,...\n      Specify a comma-separated list of category-filters to apply: only\n      error messages whose category names pass the filters will be printed.\n      (Category names are printed with the message and look like\n      \"[whitespace/indent]\".)  Filters are evaluated left to right.\n      \"-FOO\" and \"FOO\" means \"do not print categories that start with FOO\".\n      \"+FOO\" means \"do print categories that start with FOO\".\n\n      Examples: --filter=-whitespace,+whitespace/braces\n                --filter=whitespace,runtime/printf,+runtime/printf_format\n                --filter=-,+build/include_what_you_use\n\n      To see a list of all the categories used in cpplint, pass no arg:\n         --filter=\n\n    counting=total|toplevel|detailed\n      The total number of errors found is always printed. If\n      'toplevel' is provided, then the count of errors in each of\n      the top-level categories like 'build' and 'whitespace' will\n      also be printed. If 'detailed' is provided, then a count\n      is provided for each category like 'build/class'.\n\"\"\" % (EXTENSIONS)\n\n# We categorize each error message we print.  Here are the categories.\n# We want an explicit list so we can list them all in cpplint --filter=.\n# If you add a new error message with a new category, add it to the list\n# here!  cpplint_unittest.py should tell you if you forget to do this.\n# \\ used for clearer layout -- pylint: disable-msg=C6013\n_ERROR_CATEGORIES = [\n  'build/class',\n  'build/deprecated',\n  'build/endif_comment',\n  'build/explicit_make_pair',\n  'build/forward_decl',\n  'build/header_guard',\n  'build/include',\n  'build/include_alpha',\n  'build/include_order',\n  'build/include_what_you_use',\n  'build/namespaces',\n  'build/printf_format',\n  'build/storage_class',\n  'legal/copyright',\n  'readability/braces',\n  'readability/casting',\n  'readability/check',\n  'readability/constructors',\n  'readability/fn_size',\n  'readability/function',\n  'readability/multiline_comment',\n  'readability/multiline_string',\n  'readability/nolint',\n  'readability/streams',\n  'readability/todo',\n  'readability/utf8',\n  'runtime/arrays',\n  'runtime/casting',\n  'runtime/explicit',\n  'runtime/int',\n  'runtime/init',\n  'runtime/invalid_increment',\n  'runtime/member_string_references',\n  'runtime/memset',\n  'runtime/operator',\n  'runtime/printf',\n  'runtime/printf_format',\n  'runtime/references',\n  'runtime/rtti',\n  'runtime/sizeof',\n  'runtime/string',\n  'runtime/threadsafe_fn',\n  'runtime/virtual',\n  'whitespace/blank_line',\n  'whitespace/braces',\n  'whitespace/comma',\n  'whitespace/comments',\n  'whitespace/end_of_line',\n  'whitespace/ending_newline',\n  'whitespace/indent',\n  'whitespace/labels',\n  'whitespace/line_length',\n  'whitespace/newline',\n  'whitespace/operators',\n  'whitespace/parens',\n  'whitespace/semicolon',\n  'whitespace/tab',\n  'whitespace/todo'\n  ]\n\n# The default state of the category filter. This is overrided by the --filter=\n# flag. By default all errors are on, so only add here categories that should be\n# off by default (i.e., categories that must be enabled by the --filter= flags).\n# All entries here should start with a '-' or '+', as in the --filter= flag.\n_DEFAULT_FILTERS = ['-build/include_alpha']\n\n# We used to check for high-bit characters, but after much discussion we\n# decided those were OK, as long as they were in UTF-8 and didn't represent\n# hard-coded international strings, which belong in a separate i18n file.\n\n# Headers that we consider STL headers.\n_STL_HEADERS = frozenset([\n    'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',\n    'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',\n    'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new',\n    'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',\n    'stl_alloc.h', 'stl_relops.h', 'type_traits.h',\n    'utility', 'vector', 'vector.h',\n    ])\n\n\n# Non-STL C++ system headers.\n_CPP_HEADERS = frozenset([\n    'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',\n    'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',\n    'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',\n    'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',\n    'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',\n    'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',\n    'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream',\n    'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',\n    'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h',\n    'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h',\n    'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',\n    'stdiostream.h', 'streambuf.h', 'stream.h', 'strfile.h', 'string',\n    'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo', 'valarray',\n    ])\n\n\n# Assertion macros.  These are defined in base/logging.h and\n# testing/base/gunit.h.  Note that the _M versions need to come first\n# for substring matching to work.\n_CHECK_MACROS = [\n    'DCHECK', 'CHECK',\n    'EXPECT_TRUE_M', 'EXPECT_TRUE',\n    'ASSERT_TRUE_M', 'ASSERT_TRUE',\n    'EXPECT_FALSE_M', 'EXPECT_FALSE',\n    'ASSERT_FALSE_M', 'ASSERT_FALSE',\n    ]\n\n# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE\n_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])\n\nfor op, replacement in [('==', 'EQ'), ('!=', 'NE'),\n                        ('>=', 'GE'), ('>', 'GT'),\n                        ('<=', 'LE'), ('<', 'LT')]:\n  _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement\n  _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement\n  _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement\n  _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement\n  _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement\n  _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement\n\nfor op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),\n                            ('>=', 'LT'), ('>', 'LE'),\n                            ('<=', 'GT'), ('<', 'GE')]:\n  _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement\n  _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement\n  _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement\n  _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement\n\n\n# These constants define types of headers for use with\n# _IncludeState.CheckNextIncludeOrder().\n_C_SYS_HEADER = 1\n_CPP_SYS_HEADER = 2\n_LIKELY_MY_HEADER = 3\n_POSSIBLE_MY_HEADER = 4\n_OTHER_HEADER = 5\n\n\n_regexp_compile_cache = {}\n\n# Finds occurrences of NOLINT or NOLINT(...).\n_RE_SUPPRESSION = re.compile(r'\\bNOLINT\\b(\\([^)]*\\))?')\n\n# {str, set(int)}: a map from error categories to sets of linenumbers\n# on which those errors are expected and should be suppressed.\n_error_suppressions = {}\n\n\nif sys.version_info < (3,):\n    def u(x):\n        return codecs.unicode_escape_decode(x)[0]\n    TEXT_TYPE = unicode\n    # BINARY_TYPE = str\n    range = xrange\n    itervalues = dict.itervalues\n    iteritems = dict.iteritems\nelse:\n    def u(x):\n        return x\n    TEXT_TYPE = str\n    # BINARY_TYPE = bytes\n    itervalues = dict.values\n    iteritems = dict.items\n\ndef ParseNolintSuppressions(filename, raw_line, linenum, error):\n  \"\"\"Updates the global list of error-suppressions.\n\n  Parses any NOLINT comments on the current line, updating the global\n  error_suppressions store.  Reports an error if the NOLINT comment\n  was malformed.\n\n  Args:\n    filename: str, the name of the input file.\n    raw_line: str, the line of input text, with comments.\n    linenum: int, the number of the current line.\n    error: function, an error handler.\n  \"\"\"\n  # FIXME(adonovan): \"NOLINT(\" is misparsed as NOLINT(*).\n  matched = _RE_SUPPRESSION.search(raw_line)\n  if matched:\n    category = matched.group(1)\n    if category in (None, '(*)'):  # => \"suppress all\"\n      _error_suppressions.setdefault(None, set()).add(linenum)\n    else:\n      if category.startswith('(') and category.endswith(')'):\n        category = category[1:-1]\n        if category in _ERROR_CATEGORIES:\n          _error_suppressions.setdefault(category, set()).add(linenum)\n        else:\n          error(filename, linenum, 'readability/nolint', 5,\n                'Unknown NOLINT error category: %s' % category)\n\n\ndef ResetNolintSuppressions():\n  \"Resets the set of NOLINT suppressions to empty.\"\n  _error_suppressions.clear()\n\n\ndef IsErrorSuppressedByNolint(category, linenum):\n  \"\"\"Returns true if the specified error category is suppressed on this line.\n\n  Consults the global error_suppressions map populated by\n  ParseNolintSuppressions/ResetNolintSuppressions.\n\n  Args:\n    category: str, the category of the error.\n    linenum: int, the current line number.\n  Returns:\n    bool, True iff the error should be suppressed due to a NOLINT comment.\n  \"\"\"\n  return (linenum in _error_suppressions.get(category, set()) or\n          linenum in _error_suppressions.get(None, set()))\n\ndef Match(pattern, s):\n  \"\"\"Matches the string with the pattern, caching the compiled regexp.\"\"\"\n  # The regexp compilation caching is inlined in both Match and Search for\n  # performance reasons; factoring it out into a separate function turns out\n  # to be noticeably expensive.\n  if not pattern in _regexp_compile_cache:\n    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)\n  return _regexp_compile_cache[pattern].match(s)\n\n\ndef Search(pattern, s):\n  \"\"\"Searches the string for the pattern, caching the compiled regexp.\"\"\"\n  if not pattern in _regexp_compile_cache:\n    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)\n  return _regexp_compile_cache[pattern].search(s)\n\n\nclass _IncludeState(dict):\n  \"\"\"Tracks line numbers for includes, and the order in which includes appear.\n\n  As a dict, an _IncludeState object serves as a mapping between include\n  filename and line number on which that file was included.\n\n  Call CheckNextIncludeOrder() once for each header in the file, passing\n  in the type constants defined above. Calls in an illegal order will\n  raise an _IncludeError with an appropriate error message.\n\n  \"\"\"\n  # self._section will move monotonically through this set. If it ever\n  # needs to move backwards, CheckNextIncludeOrder will raise an error.\n  _INITIAL_SECTION = 0\n  _MY_H_SECTION = 1\n  _C_SECTION = 2\n  _CPP_SECTION = 3\n  _OTHER_H_SECTION = 4\n\n  _TYPE_NAMES = {\n      _C_SYS_HEADER: 'C system header',\n      _CPP_SYS_HEADER: 'C++ system header',\n      _LIKELY_MY_HEADER: 'header this file implements',\n      _POSSIBLE_MY_HEADER: 'header this file may implement',\n      _OTHER_HEADER: 'other header',\n      }\n  _SECTION_NAMES = {\n      _INITIAL_SECTION: \"... nothing. (This can't be an error.)\",\n      _MY_H_SECTION: 'a header this file implements',\n      _C_SECTION: 'C system header',\n      _CPP_SECTION: 'C++ system header',\n      _OTHER_H_SECTION: 'other header',\n      }\n\n  def __init__(self):\n    dict.__init__(self)\n    # The name of the current section.\n    self._section = self._INITIAL_SECTION\n    # The path of last found header.\n    self._last_header = ''\n\n  def CanonicalizeAlphabeticalOrder(self, header_path):\n    \"\"\"Returns a path canonicalized for alphabetical comparison.\n\n    - replaces \"-\" with \"_\" so they both cmp the same.\n    - removes '-inl' since we don't require them to be after the main header.\n    - lowercase everything, just in case.\n\n    Args:\n      header_path: Path to be canonicalized.\n\n    Returns:\n      Canonicalized path.\n    \"\"\"\n    return header_path.replace('-inl.h', '.h').replace('-', '_').lower()\n\n  def IsInAlphabeticalOrder(self, header_path):\n    \"\"\"Check if a header is in alphabetical order with the previous header.\n\n    Args:\n      header_path: Header to be checked.\n\n    Returns:\n      Returns true if the header is in alphabetical order.\n    \"\"\"\n    canonical_header = self.CanonicalizeAlphabeticalOrder(header_path)\n    if self._last_header > canonical_header:\n      return False\n    self._last_header = canonical_header\n    return True\n\n  def CheckNextIncludeOrder(self, header_type):\n    \"\"\"Returns a non-empty error message if the next header is out of order.\n\n    This function also updates the internal state to be ready to check\n    the next include.\n\n    Args:\n      header_type: One of the _XXX_HEADER constants defined above.\n\n    Returns:\n      The empty string if the header is in the right order, or an\n      error message describing what's wrong.\n\n    \"\"\"\n    error_message = ('Found %s after %s' %\n                     (self._TYPE_NAMES[header_type],\n                      self._SECTION_NAMES[self._section]))\n\n    last_section = self._section\n\n    if header_type == _C_SYS_HEADER:\n      if self._section <= self._C_SECTION:\n        self._section = self._C_SECTION\n      else:\n        self._last_header = ''\n        return error_message\n    elif header_type == _CPP_SYS_HEADER:\n      if self._section <= self._CPP_SECTION:\n        self._section = self._CPP_SECTION\n      else:\n        self._last_header = ''\n        return error_message\n    elif header_type == _LIKELY_MY_HEADER:\n      if self._section <= self._MY_H_SECTION:\n        self._section = self._MY_H_SECTION\n      else:\n        self._section = self._OTHER_H_SECTION\n    elif header_type == _POSSIBLE_MY_HEADER:\n      if self._section <= self._MY_H_SECTION:\n        self._section = self._MY_H_SECTION\n      else:\n        # This will always be the fallback because we're not sure\n        # enough that the header is associated with this file.\n        self._section = self._OTHER_H_SECTION\n    else:\n      assert header_type == _OTHER_HEADER\n      self._section = self._OTHER_H_SECTION\n\n    if last_section != self._section:\n      self._last_header = ''\n\n    return ''\n\n\nclass _CppLintState(object):\n  \"\"\"Maintains module-wide state..\"\"\"\n\n  def __init__(self):\n    self.verbose_level = 1  # global setting.\n    self.error_count = 0    # global count of reported errors\n    # filters to apply when emitting error messages\n    self.filters = _DEFAULT_FILTERS[:]\n    self.counting = 'total'  # In what way are we counting errors?\n    self.errors_by_category = {}  # string to int dict storing error counts\n\n    # output format:\n    # \"emacs\" - format that emacs can parse (default)\n    # \"vs7\" - format that Microsoft Visual Studio 7 can parse\n    self.output_format = 'emacs'\n\n  def SetOutputFormat(self, output_format):\n    \"\"\"Sets the output format for errors.\"\"\"\n    self.output_format = output_format\n\n  def SetVerboseLevel(self, level):\n    \"\"\"Sets the module's verbosity, and returns the previous setting.\"\"\"\n    last_verbose_level = self.verbose_level\n    self.verbose_level = level\n    return last_verbose_level\n\n  def SetCountingStyle(self, counting_style):\n    \"\"\"Sets the module's counting options.\"\"\"\n    self.counting = counting_style\n\n  def SetFilters(self, filters):\n    \"\"\"Sets the error-message filters.\n\n    These filters are applied when deciding whether to emit a given\n    error message.\n\n    Args:\n      filters: A string of comma-separated filters (eg \"+whitespace/indent\").\n               Each filter should start with + or -; else we die.\n\n    Raises:\n      ValueError: The comma-separated filters did not all start with '+' or '-'.\n                  E.g. \"-,+whitespace,-whitespace/indent,whitespace/badfilter\"\n    \"\"\"\n    # Default filters always have less priority than the flag ones.\n    self.filters = _DEFAULT_FILTERS[:]\n    for filt in filters.split(','):\n      clean_filt = filt.strip()\n      if clean_filt:\n        self.filters.append(clean_filt)\n    for filt in self.filters:\n      if not (filt.startswith('+') or filt.startswith('-')):\n        raise ValueError('Every filter in --filters must start with + or -'\n                         ' (%s does not)' % filt)\n\n  def ResetErrorCounts(self):\n    \"\"\"Sets the module's error statistic back to zero.\"\"\"\n    self.error_count = 0\n    self.errors_by_category = {}\n\n  def IncrementErrorCount(self, category):\n    \"\"\"Bumps the module's error statistic.\"\"\"\n    self.error_count += 1\n    if self.counting in ('toplevel', 'detailed'):\n      if self.counting != 'detailed':\n        category = category.split('/')[0]\n      if category not in self.errors_by_category:\n        self.errors_by_category[category] = 0\n      self.errors_by_category[category] += 1\n\n  def PrintErrorCounts(self):\n    \"\"\"Print a summary of errors by category, and the total.\"\"\"\n    for category, count in iteritems(self.errors_by_category):\n      sys.stderr.write('Category \\'%s\\' errors found: %d\\n' %\n                       (category, count))\n    if self.error_count:\n      sys.stderr.write('Total errors found: %d\\n' % self.error_count)\n\n_cpplint_state = _CppLintState()\n\n\ndef _OutputFormat():\n  \"\"\"Gets the module's output format.\"\"\"\n  return _cpplint_state.output_format\n\n\ndef _SetOutputFormat(output_format):\n  \"\"\"Sets the module's output format.\"\"\"\n  _cpplint_state.SetOutputFormat(output_format)\n\n\ndef _VerboseLevel():\n  \"\"\"Returns the module's verbosity setting.\"\"\"\n  return _cpplint_state.verbose_level\n\n\ndef _SetVerboseLevel(level):\n  \"\"\"Sets the module's verbosity, and returns the previous setting.\"\"\"\n  return _cpplint_state.SetVerboseLevel(level)\n\n\ndef _SetCountingStyle(level):\n  \"\"\"Sets the module's counting options.\"\"\"\n  _cpplint_state.SetCountingStyle(level)\n\n\ndef _Filters():\n  \"\"\"Returns the module's list of output filters, as a list.\"\"\"\n  return _cpplint_state.filters\n\n\ndef _SetFilters(filters):\n  \"\"\"Sets the module's error-message filters.\n\n  These filters are applied when deciding whether to emit a given\n  error message.\n\n  Args:\n    filters: A string of comma-separated filters (eg \"whitespace/indent\").\n             Each filter should start with + or -; else we die.\n  \"\"\"\n  _cpplint_state.SetFilters(filters)\n\n\nclass _FunctionState(object):\n  \"\"\"Tracks current function name and the number of lines in its body.\"\"\"\n\n  _NORMAL_TRIGGER = 250  # for --v=0, 500 for --v=1, etc.\n  _TEST_TRIGGER = 400    # about 50% more than _NORMAL_TRIGGER.\n\n  def __init__(self):\n    self.in_a_function = False\n    self.lines_in_function = 0\n    self.current_function = ''\n\n  def Begin(self, function_name):\n    \"\"\"Start analyzing function body.\n\n    Args:\n      function_name: The name of the function being tracked.\n    \"\"\"\n    self.in_a_function = True\n    self.lines_in_function = 0\n    self.current_function = function_name\n\n  def Count(self):\n    \"\"\"Count line in current function body.\"\"\"\n    if self.in_a_function:\n      self.lines_in_function += 1\n\n  def Check(self, error, filename, linenum):\n    \"\"\"Report if too many lines in function body.\n\n    Args:\n      error: The function to call with any errors found.\n      filename: The name of the current file.\n      linenum: The number of the line to check.\n    \"\"\"\n    if Match(r'T(EST|est)', self.current_function):\n      base_trigger = self._TEST_TRIGGER\n    else:\n      base_trigger = self._NORMAL_TRIGGER\n    trigger = base_trigger * 2**_VerboseLevel()\n\n    if self.lines_in_function > trigger:\n      error_level = int(math.log(self.lines_in_function / base_trigger, 2))\n      # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...\n      if error_level > 5:\n        error_level = 5\n      error(filename, linenum, 'readability/fn_size', error_level,\n            'Small and focused functions are preferred:'\n            ' %s has %d non-comment lines'\n            ' (error triggered by exceeding %d lines).'  % (\n                self.current_function, self.lines_in_function, trigger))\n\n  def End(self):\n    \"\"\"Stop analyzing function body.\"\"\"\n    self.in_a_function = False\n\n\nclass _IncludeError(Exception):\n  \"\"\"Indicates a problem with the include order in a file.\"\"\"\n  pass\n\n\nclass FileInfo:\n  \"\"\"Provides utility functions for filenames.\n\n  FileInfo provides easy access to the components of a file's path\n  relative to the project root.\n  \"\"\"\n\n  def __init__(self, filename):\n    self._filename = filename\n\n  def FullName(self):\n    \"\"\"Make Windows paths like Unix.\"\"\"\n    return os.path.abspath(self._filename).replace('\\\\', '/')\n\n  def RepositoryName(self):\n    \"\"\"FullName after removing the local path to the repository.\n\n    If we have a real absolute path name here we can try to do something smart:\n    detecting the root of the checkout and truncating /path/to/checkout from\n    the name so that we get header guards that don't include things like\n    \"C:\\Documents and Settings\\...\" or \"/home/username/...\" in them and thus\n    people on different computers who have checked the source out to different\n    locations won't see bogus errors.\n    \"\"\"\n    fullname = self.FullName()\n\n    if os.path.exists(fullname):\n      project_dir = os.path.dirname(fullname)\n\n      if os.path.exists(os.path.join(project_dir, \".svn\")):\n        # If there's a .svn file in the current directory, we recursively look\n        # up the directory tree for the top of the SVN checkout\n        root_dir = project_dir\n        one_up_dir = os.path.dirname(root_dir)\n        while os.path.exists(os.path.join(one_up_dir, \".svn\")):\n          root_dir = os.path.dirname(root_dir)\n          one_up_dir = os.path.dirname(one_up_dir)\n\n        prefix = os.path.commonprefix([root_dir, project_dir])\n        return fullname[len(prefix) + 1:]\n\n      # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by\n      # searching up from the current path.\n      root_dir = os.path.dirname(fullname)\n      while (root_dir != os.path.dirname(root_dir) and\n             not os.path.exists(os.path.join(root_dir, \".git\")) and\n             not os.path.exists(os.path.join(root_dir, \".hg\")) and\n             not os.path.exists(os.path.join(root_dir, \".svn\"))):\n        root_dir = os.path.dirname(root_dir)\n\n      if (os.path.exists(os.path.join(root_dir, \".git\")) or\n          os.path.exists(os.path.join(root_dir, \".hg\")) or\n          os.path.exists(os.path.join(root_dir, \".svn\"))):\n        prefix = os.path.commonprefix([root_dir, project_dir])\n        return fullname[len(prefix) + 1:]\n\n    # Don't know what to do; header guard warnings may be wrong...\n    return fullname\n\n  def Split(self):\n    \"\"\"Splits the file into the directory, basename, and extension.\n\n    For 'chrome/browser/browser.cc', Split() would\n    return ('chrome/browser', 'browser', '.cc')\n\n    Returns:\n      A tuple of (directory, basename, extension).\n    \"\"\"\n\n    googlename = self.RepositoryName()\n    project, rest = os.path.split(googlename)\n    return (project,) + os.path.splitext(rest)\n\n  def BaseName(self):\n    \"\"\"File base name - text after the final slash, before the final period.\"\"\"\n    return self.Split()[1]\n\n  def Extension(self):\n    \"\"\"File extension - text following the final period.\"\"\"\n    return self.Split()[2]\n\n  def NoExtension(self):\n    \"\"\"File has no source file extension.\"\"\"\n    return '/'.join(self.Split()[0:2])\n\n  def IsSource(self):\n    \"\"\"File has a source file extension.\"\"\"\n    return self.Extension()[1:] in EXTENSIONS\n\n\ndef _ShouldPrintError(category, confidence, linenum):\n  \"\"\"If confidence >= verbose, category passes filter and is not suppressed.\"\"\"\n\n  # There are three ways we might decide not to print an error message:\n  # a \"NOLINT(category)\" comment appears in the source,\n  # the verbosity level isn't high enough, or the filters filter it out.\n  if IsErrorSuppressedByNolint(category, linenum):\n    return False\n  if confidence < _cpplint_state.verbose_level:\n    return False\n\n  is_filtered = False\n  for one_filter in _Filters():\n    if one_filter.startswith('-'):\n      if category.startswith(one_filter[1:]):\n        is_filtered = True\n    elif one_filter.startswith('+'):\n      if category.startswith(one_filter[1:]):\n        is_filtered = False\n    else:\n      assert False  # should have been checked for in SetFilter.\n  if is_filtered:\n    return False\n\n  return True\n\n\ndef Error(filename, linenum, category, confidence, message):\n  \"\"\"Logs the fact we've found a lint error.\n\n  We log where the error was found, and also our confidence in the error,\n  that is, how certain we are this is a legitimate style regression, and\n  not a misidentification or a use that's sometimes justified.\n\n  False positives can be suppressed by the use of\n  \"cpplint(category)\"  comments on the offending line.  These are\n  parsed into _error_suppressions.\n\n  Args:\n    filename: The name of the file containing the error.\n    linenum: The number of the line containing the error.\n    category: A string used to describe the \"category\" this bug\n      falls under: \"whitespace\", say, or \"runtime\".  Categories\n      may have a hierarchy separated by slashes: \"whitespace/indent\".\n    confidence: A number from 1-5 representing a confidence score for\n      the error, with 5 meaning that we are certain of the problem,\n      and 1 meaning that it could be a legitimate construct.\n    message: The error message.\n  \"\"\"\n  if _ShouldPrintError(category, confidence, linenum):\n    _cpplint_state.IncrementErrorCount(category)\n    if _cpplint_state.output_format == 'vs7':\n      sys.stderr.write('%s(%s):  %s  [%s] [%d]\\n' % (\n          filename, linenum, message, category, confidence))\n    else:\n      m = '%s:%s:  %s  [%s] [%d]\\n' % (\n          filename, linenum, message, category, confidence)\n      sys.stderr.write(m)\n\n# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard.\n_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(\n    r'\\\\([abfnrtv?\"\\\\\\']|\\d+|x[0-9a-fA-F]+)')\n# Matches strings.  Escape codes should already be removed by ESCAPES.\n_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'\"[^\"]*\"')\n# Matches characters.  Escape codes should already be removed by ESCAPES.\n_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r\"'.'\")\n# Matches multi-line C++ comments.\n# This RE is a little bit more complicated than one might expect, because we\n# have to take care of space removals tools so we can handle comments inside\n# statements better.\n# The current rule is: We only clear spaces from both sides when we're at the\n# end of the line. Otherwise, we try to remove spaces from the right side,\n# if this doesn't work we try on left side but only if there's a non-character\n# on the right.\n_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(\n    r\"\"\"(\\s*/\\*.*\\*/\\s*$|\n            /\\*.*\\*/\\s+|\n         \\s+/\\*.*\\*/(?=\\W)|\n            /\\*.*\\*/)\"\"\", re.VERBOSE)\n\n\ndef IsCppString(line):\n  \"\"\"Does line terminate so, that the next symbol is in string constant.\n\n  This function does not consider single-line nor multi-line comments.\n\n  Args:\n    line: is a partial line of code starting from the 0..n.\n\n  Returns:\n    True, if next character appended to 'line' is inside a\n    string constant.\n  \"\"\"\n\n  line = line.replace(r'\\\\', 'XX')  # after this, \\\\\" does not match to \\\"\n  return ((line.count('\"') - line.count(r'\\\"') - line.count(\"'\\\"'\")) & 1) == 1\n\n\ndef FindNextMultiLineCommentStart(lines, lineix):\n  \"\"\"Find the beginning marker for a multiline comment.\"\"\"\n  while lineix < len(lines):\n    if lines[lineix].strip().startswith('/*'):\n      # Only return this marker if the comment goes beyond this line\n      if lines[lineix].strip().find('*/', 2) < 0:\n        return lineix\n    lineix += 1\n  return len(lines)\n\n\ndef FindNextMultiLineCommentEnd(lines, lineix):\n  \"\"\"We are inside a comment, find the end marker.\"\"\"\n  while lineix < len(lines):\n    if lines[lineix].strip().endswith('*/'):\n      return lineix\n    lineix += 1\n  return len(lines)\n\n\ndef RemoveMultiLineCommentsFromRange(lines, begin, end):\n  \"\"\"Clears a range of lines for multi-line comments.\"\"\"\n  # Having // dummy comments makes the lines non-empty, so we will not get\n  # unnecessary blank line warnings later in the code.\n  for i in range(begin, end):\n    lines[i] = '// dummy'\n\n\ndef RemoveMultiLineComments(filename, lines, error):\n  \"\"\"Removes multiline (c-style) comments from lines.\"\"\"\n  lineix = 0\n  while lineix < len(lines):\n    lineix_begin = FindNextMultiLineCommentStart(lines, lineix)\n    if lineix_begin >= len(lines):\n      return\n    lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)\n    if lineix_end >= len(lines):\n      error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,\n            'Could not find end of multi-line comment')\n      return\n    RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)\n    lineix = lineix_end + 1\n\n\ndef CleanseComments(line):\n  \"\"\"Removes //-comments and single-line C-style /* */ comments.\n\n  Args:\n    line: A line of C++ source.\n\n  Returns:\n    The line with single-line comments removed.\n  \"\"\"\n  commentpos = line.find('//')\n  if commentpos != -1 and not IsCppString(line[:commentpos]):\n    line = line[:commentpos].rstrip()\n  # get rid of /* ... */\n  return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)\n\n\nclass CleansedLines(object):\n  \"\"\"Holds 3 copies of all lines with different preprocessing applied to them.\n\n  1) elided member contains lines without strings and comments,\n  2) lines member contains lines without comments, and\n  3) raw member contains all the lines without processing.\n  All these three members are of <type 'list'>, and of the same length.\n  \"\"\"\n\n  def __init__(self, lines):\n    self.elided = []\n    self.lines = []\n    self.raw_lines = lines\n    self.num_lines = len(lines)\n    for linenum in range(len(lines)):\n      self.lines.append(CleanseComments(lines[linenum]))\n      elided = self._CollapseStrings(lines[linenum])\n      self.elided.append(CleanseComments(elided))\n\n  def NumLines(self):\n    \"\"\"Returns the number of lines represented.\"\"\"\n    return self.num_lines\n\n  @staticmethod\n  def _CollapseStrings(elided):\n    \"\"\"Collapses strings and chars on a line to simple \"\" or '' blocks.\n\n    We nix strings first so we're not fooled by text like '\"http://\"'\n\n    Args:\n      elided: The line being processed.\n\n    Returns:\n      The line with collapsed strings.\n    \"\"\"\n    if not _RE_PATTERN_INCLUDE.match(elided):\n      # Remove escaped characters first to make quote/single quote collapsing\n      # basic.  Things that look like escaped characters shouldn't occur\n      # outside of strings and chars.\n      elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)\n      elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub(\"''\", elided)\n      elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('\"\"', elided)\n    return elided\n\n\ndef CloseExpression(clean_lines, linenum, pos):\n  \"\"\"If input points to ( or { or [, finds the position that closes it.\n\n  If lines[linenum][pos] points to a '(' or '{' or '[', finds the\n  linenum/pos that correspond to the closing of the expression.\n\n  Args:\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    pos: A position on the line.\n\n  Returns:\n    A tuple (line, linenum, pos) pointer *past* the closing brace, or\n    (line, len(lines), -1) if we never find a close.  Note we ignore\n    strings and comments when matching; and the line we return is the\n    'cleansed' line at linenum.\n  \"\"\"\n\n  line = clean_lines.elided[linenum]\n  startchar = line[pos]\n  if startchar not in '({[':\n    return (line, clean_lines.NumLines(), -1)\n  if startchar == '(': endchar = ')'\n  if startchar == '[': endchar = ']'\n  if startchar == '{': endchar = '}'\n\n  num_open = line.count(startchar) - line.count(endchar)\n  while linenum < clean_lines.NumLines() and num_open > 0:\n    linenum += 1\n    line = clean_lines.elided[linenum]\n    num_open += line.count(startchar) - line.count(endchar)\n  # OK, now find the endchar that actually got us back to even\n  endpos = len(line)\n  while num_open >= 0:\n    endpos = line.rfind(')', 0, endpos)\n    num_open -= 1                 # chopped off another )\n  return (line, linenum, endpos + 1)\n\n\ndef CheckForCopyright(filename, lines, error):\n  \"\"\"Logs an error if no Copyright message appears at the top of the file.\"\"\"\n\n  # We'll say it should occur by line 10. Don't forget there's a\n  # dummy line at the front.\n  for line in range(1, min(len(lines), 11)):\n    if re.search(r'Copyright', lines[line], re.I):\n      break\n  else:                       # means no copyright line was found\n    error(filename, 0, 'legal/copyright', 5,\n          'No copyright message found.  '\n          'You should have a line: \"Copyright [year] <Copyright Owner>\"')\n\n\ndef GetHeaderGuardCPPVariable(filename):\n  \"\"\"Returns the CPP variable that should be used as a header guard.\n\n  Args:\n    filename: The name of a C++ header file.\n\n  Returns:\n    The CPP variable that should be used as a header guard in the\n    named file.\n\n  \"\"\"\n\n  # Restores original filename in case that cpplint is invoked from Emacs's\n  # flymake.\n  filename = re.sub(r'_flymake\\.h$', '.h', filename)\n\n  fileinfo = FileInfo(filename)\n  return re.sub(r'[-./\\s]', '_', fileinfo.RepositoryName()).upper() + '_'\n\n\ndef CheckForHeaderGuard(filename, lines, error):\n  \"\"\"Checks that the file contains a header guard.\n\n  Logs an error if no #ifndef header guard is present.  For other\n  headers, checks that the full pathname is used.\n\n  Args:\n    filename: The name of the C++ header file.\n    lines: An array of strings, each representing a line of the file.\n    error: The function to call with any errors found.\n  \"\"\"\n\n  cppvar = GetHeaderGuardCPPVariable(filename)\n\n  ifndef = None\n  ifndef_linenum = 0\n  define = None\n  endif = None\n  endif_linenum = 0\n  for linenum, line in enumerate(lines):\n    linesplit = line.split()\n    if len(linesplit) >= 2:\n      # find the first occurrence of #ifndef and #define, save arg\n      if not ifndef and linesplit[0] == '#ifndef':\n        # set ifndef to the header guard presented on the #ifndef line.\n        ifndef = linesplit[1]\n        ifndef_linenum = linenum\n      if not define and linesplit[0] == '#define':\n        define = linesplit[1]\n    # find the last occurrence of #endif, save entire line\n    if line.startswith('#endif'):\n      endif = line\n      endif_linenum = linenum\n\n  if not ifndef:\n    error(filename, 0, 'build/header_guard', 5,\n          'No #ifndef header guard found, suggested CPP variable is: %s' %\n          cppvar)\n    return\n\n  if not define:\n    error(filename, 0, 'build/header_guard', 5,\n          'No #define header guard found, suggested CPP variable is: %s' %\n          cppvar)\n    return\n\n  # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__\n  # for backward compatibility.\n  if ifndef != cppvar:\n    error_level = 0\n    if ifndef != cppvar + '_':\n      error_level = 5\n\n    ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum,\n                            error)\n    error(filename, ifndef_linenum, 'build/header_guard', error_level,\n          '#ifndef header guard has wrong style, please use: %s' % cppvar)\n\n  if define != ifndef:\n    error(filename, 0, 'build/header_guard', 5,\n          '#ifndef and #define don\\'t match, suggested CPP variable is: %s' %\n          cppvar)\n    return\n\n  if endif != ('#endif  // %s' % cppvar):\n    error_level = 0\n    if endif != ('#endif  // %s' % (cppvar + '_')):\n      error_level = 5\n\n    ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum,\n                            error)\n    error(filename, endif_linenum, 'build/header_guard', error_level,\n          '#endif line should be \"#endif  // %s\"' % cppvar)\n\n\ndef CheckForUnicodeReplacementCharacters(filename, lines, error):\n  \"\"\"Logs an error for each line containing Unicode replacement characters.\n\n  These indicate that either the file contained invalid UTF-8 (likely)\n  or Unicode replacement characters (which it shouldn't).  Note that\n  it's possible for this to throw off line numbering if the invalid\n  UTF-8 occurred adjacent to a newline.\n\n  Args:\n    filename: The name of the current file.\n    lines: An array of strings, each representing a line of the file.\n    error: The function to call with any errors found.\n  \"\"\"\n  for linenum, line in enumerate(lines):\n    if u('\\ufffd') in line:\n      error(filename, linenum, 'readability/utf8', 5,\n            'Line contains invalid UTF-8 (or Unicode replacement character).')\n\n\ndef CheckForNewlineAtEOF(filename, lines, error):\n  \"\"\"Logs an error if there is no newline char at the end of the file.\n\n  Args:\n    filename: The name of the current file.\n    lines: An array of strings, each representing a line of the file.\n    error: The function to call with any errors found.\n  \"\"\"\n\n  # The array lines() was created by adding two newlines to the\n  # original file (go figure), then splitting on \\n.\n  # To verify that the file ends in \\n, we just have to make sure the\n  # last-but-two element of lines() exists and is empty.\n  if len(lines) < 3 or lines[-2]:\n    error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,\n          'Could not find a newline character at the end of the file.')\n\n\ndef CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):\n  \"\"\"Logs an error if we see /* ... */ or \"...\" that extend past one line.\n\n  /* ... */ comments are legit inside macros, for one line.\n  Otherwise, we prefer // comments, so it's ok to warn about the\n  other.  Likewise, it's ok for strings to extend across multiple\n  lines, as long as a line continuation character (backslash)\n  terminates each line. Although not currently prohibited by the C++\n  style guide, it's ugly and unnecessary. We don't do well with either\n  in this lint program, so we warn about both.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n  line = clean_lines.elided[linenum]\n\n  # Remove all \\\\ (escaped backslashes) from the line. They are OK, and the\n  # second (escaped) slash may trigger later \\\" detection erroneously.\n  line = line.replace('\\\\\\\\', '')\n\n  if line.count('/*') > line.count('*/'):\n    error(filename, linenum, 'readability/multiline_comment', 5,\n          'Complex multi-line /*...*/-style comment found. '\n          'Lint may give bogus warnings.  '\n          'Consider replacing these with //-style comments, '\n          'with #if 0...#endif, '\n          'or with more clearly structured multi-line comments.')\n\n  if (line.count('\"') - line.count('\\\\\"')) % 2:\n    error(filename, linenum, 'readability/multiline_string', 5,\n          'Multi-line string (\"...\") found.  This lint script doesn\\'t '\n          'do well with such strings, and may give bogus warnings.  They\\'re '\n          'ugly and unnecessary, and you should use concatenation instead\".')\n\n\nthreading_list = (\n    ('asctime(', 'asctime_r('),\n    ('ctime(', 'ctime_r('),\n    ('getgrgid(', 'getgrgid_r('),\n    ('getgrnam(', 'getgrnam_r('),\n    ('getlogin(', 'getlogin_r('),\n    ('getpwnam(', 'getpwnam_r('),\n    ('getpwuid(', 'getpwuid_r('),\n    ('gmtime(', 'gmtime_r('),\n    ('localtime(', 'localtime_r('),\n    ('rand(', 'rand_r('),\n    ('readdir(', 'readdir_r('),\n    ('strtok(', 'strtok_r('),\n    ('ttyname(', 'ttyname_r('),\n    )\n\n\ndef CheckPosixThreading(filename, clean_lines, linenum, error):\n  \"\"\"Checks for calls to thread-unsafe functions.\n\n  Much code has been originally written without consideration of\n  multi-threading. Also, engineers are relying on their old experience;\n  they have learned posix before threading extensions were added. These\n  tests guide the engineers to use thread-safe functions (when using\n  posix directly).\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n  line = clean_lines.elided[linenum]\n  for single_thread_function, multithread_safe_function in threading_list:\n    ix = line.find(single_thread_function)\n    # Comparisons made explicit for clarity -- pylint: disable-msg=C6403\n    if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and\n                                line[ix - 1] not in ('_', '.', '>'))):\n      error(filename, linenum, 'runtime/threadsafe_fn', 2,\n            'Consider using ' + multithread_safe_function +\n            '...) instead of ' + single_thread_function +\n            '...) for improved thread safety.')\n\n\n# Matches invalid increment: *count++, which moves pointer instead of\n# incrementing a value.\n_RE_PATTERN_INVALID_INCREMENT = re.compile(\n    r'^\\s*\\*\\w+(\\+\\+|--);')\n\n\ndef CheckInvalidIncrement(filename, clean_lines, linenum, error):\n  \"\"\"Checks for invalid increment *count++.\n\n  For example following function:\n  void increment_counter(int* count) {\n    *count++;\n  }\n  is invalid, because it effectively does count++, moving pointer, and should\n  be replaced with ++*count, (*count)++ or *count += 1.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n  line = clean_lines.elided[linenum]\n  if _RE_PATTERN_INVALID_INCREMENT.match(line):\n    error(filename, linenum, 'runtime/invalid_increment', 5,\n          'Changing pointer instead of value (or unused value of operator*).')\n\n\nclass _ClassInfo(object):\n  \"\"\"Stores information about a class.\"\"\"\n\n  def __init__(self, name, clean_lines, linenum):\n    self.name = name\n    self.linenum = linenum\n    self.seen_open_brace = False\n    self.is_derived = False\n    self.virtual_method_linenumber = None\n    self.has_virtual_destructor = False\n    self.brace_depth = 0\n\n    # Try to find the end of the class.  This will be confused by things like:\n    #   class A {\n    #   } *x = { ...\n    #\n    # But it's still good enough for CheckSectionSpacing.\n    self.last_line = 0\n    depth = 0\n    for i in range(linenum, clean_lines.NumLines()):\n      line = clean_lines.lines[i]\n      depth += line.count('{') - line.count('}')\n      if not depth:\n        self.last_line = i\n        break\n\n\nclass _ClassState(object):\n  \"\"\"Holds the current state of the parse relating to class declarations.\n\n  It maintains a stack of _ClassInfos representing the parser's guess\n  as to the current nesting of class declarations. The innermost class\n  is at the top (back) of the stack. Typically, the stack will either\n  be empty or have exactly one entry.\n  \"\"\"\n\n  def __init__(self):\n    self.classinfo_stack = []\n\n  def CheckFinished(self, filename, error):\n    \"\"\"Checks that all classes have been completely parsed.\n\n    Call this when all lines in a file have been processed.\n    Args:\n      filename: The name of the current file.\n      error: The function to call with any errors found.\n    \"\"\"\n    if self.classinfo_stack:\n      # Note: This test can result in false positives if #ifdef constructs\n      # get in the way of brace matching. See the testBuildClass test in\n      # cpplint_unittest.py for an example of this.\n      error(filename, self.classinfo_stack[0].linenum, 'build/class', 5,\n            'Failed to find complete declaration of class %s' %\n            self.classinfo_stack[0].name)\n\n\ndef CheckForNonStandardConstructs(filename, clean_lines, linenum,\n                                  class_state, error):\n  \"\"\"Logs an error if we see certain non-ANSI constructs ignored by gcc-2.\n\n  Complain about several constructs which gcc-2 accepts, but which are\n  not standard C++.  Warning about these in lint is one way to ease the\n  transition to new compilers.\n  - put storage class first (e.g. \"static const\" instead of \"const static\").\n  - \"%lld\" instead of %qd\" in printf-type functions.\n  - \"%1$d\" is non-standard in printf-type functions.\n  - \"\\%\" is an undefined character escape sequence.\n  - text after #endif is not allowed.\n  - invalid inner-style forward declaration.\n  - >? and <? operators, and their >?= and <?= cousins.\n  - classes with virtual methods need virtual destructors (compiler warning\n    available, but not turned on yet.)\n\n  Additionally, check for constructor/destructor style violations and reference\n  members, as it is very convenient to do so while checking for\n  gcc-2 compliance.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    class_state: A _ClassState instance which maintains information about\n                 the current stack of nested class declarations being parsed.\n    error: A callable to which errors are reported, which takes 4 arguments:\n           filename, line number, error level, and message\n  \"\"\"\n\n  # Remove comments from the line, but leave in strings for now.\n  line = clean_lines.lines[linenum]\n\n  if Search(r'printf\\s*\\(.*\".*%[-+ ]?\\d*q', line):\n    error(filename, linenum, 'runtime/printf_format', 3,\n          '%q in format strings is deprecated.  Use %ll instead.')\n\n  if Search(r'printf\\s*\\(.*\".*%\\d+\\$', line):\n    error(filename, linenum, 'runtime/printf_format', 2,\n          '%N$ formats are unconventional.  Try rewriting to avoid them.')\n\n  # Remove escaped backslashes before looking for undefined escapes.\n  line = line.replace('\\\\\\\\', '')\n\n  if Search(r'(\"|\\').*\\\\(%|\\[|\\(|{)', line):\n    error(filename, linenum, 'build/printf_format', 3,\n          '%, [, (, and { are undefined character escapes.  Unescape them.')\n\n  # For the rest, work with both comments and strings removed.\n  line = clean_lines.elided[linenum]\n\n  if Search(r'\\b(const|volatile|void|char|short|int|long'\n            r'|float|double|signed|unsigned'\n            r'|schar|u?int8|u?int16|u?int32|u?int64)'\n            r'\\s+(auto|register|static|extern|typedef)\\b',\n            line):\n    error(filename, linenum, 'build/storage_class', 5,\n          'Storage class (static, extern, typedef, etc) should be first.')\n\n  if Match(r'\\s*#\\s*endif\\s*[^/\\s]+', line):\n    error(filename, linenum, 'build/endif_comment', 5,\n          'Uncommented text after #endif is non-standard.  Use a comment.')\n\n  if Match(r'\\s*class\\s+(\\w+\\s*::\\s*)+\\w+\\s*;', line):\n    error(filename, linenum, 'build/forward_decl', 5,\n          'Inner-style forward declarations are invalid.  Remove this line.')\n\n  if Search(r'(\\w+|[+-]?\\d+(\\.\\d*)?)\\s*(<|>)\\?=?\\s*(\\w+|[+-]?\\d+)(\\.\\d*)?',\n            line):\n    error(filename, linenum, 'build/deprecated', 3,\n          '>? and <? (max and min) operators are non-standard and deprecated.')\n\n  if Search(r'^\\s*const\\s*string\\s*&\\s*\\w+\\s*;', line):\n    # TODO(unknown): Could it be expanded safely to arbitrary references,\n    # without triggering too many false positives? The first\n    # attempt triggered 5 warnings for mostly benign code in the regtest, hence\n    # the restriction.\n    # Here's the original regexp, for the reference:\n    # type_name = r'\\w+((\\s*::\\s*\\w+)|(\\s*<\\s*\\w+?\\s*>))?'\n    # r'\\s*const\\s*' + type_name + '\\s*&\\s*\\w+\\s*;'\n    error(filename, linenum, 'runtime/member_string_references', 2,\n          'const string& members are dangerous. It is much better to use '\n          'alternatives, such as pointers or simple constants.')\n\n  # Track class entry and exit, and attempt to find cases within the\n  # class declaration that don't meet the C++ style\n  # guidelines. Tracking is very dependent on the code matching Google\n  # style guidelines, but it seems to perform well enough in testing\n  # to be a worthwhile addition to the checks.\n  classinfo_stack = class_state.classinfo_stack\n  # Look for a class declaration. The regexp accounts for decorated classes\n  # such as in:\n  # class LOCKABLE API Object {\n  # };\n  class_decl_match = Match(\n      r'\\s*(template\\s*<[\\w\\s<>,:]*>\\s*)?'\n      '(class|struct)\\s+([A-Z_]+\\s+)*(\\w+(::\\w+)*)', line)\n  if class_decl_match:\n    classinfo_stack.append(_ClassInfo(\n        class_decl_match.group(4), clean_lines, linenum))\n\n  # Everything else in this function uses the top of the stack if it's\n  # not empty.\n  if not classinfo_stack:\n    return\n\n  classinfo = classinfo_stack[-1]\n\n  # If the opening brace hasn't been seen look for it and also\n  # parent class declarations.\n  if not classinfo.seen_open_brace:\n    # If the line has a ';' in it, assume it's a forward declaration or\n    # a single-line class declaration, which we won't process.\n    if line.find(';') != -1:\n      classinfo_stack.pop()\n      return\n    classinfo.seen_open_brace = (line.find('{') != -1)\n    # Look for a bare ':'\n    if Search('(^|[^:]):($|[^:])', line):\n      classinfo.is_derived = True\n    if not classinfo.seen_open_brace:\n      return  # Everything else in this function is for after open brace\n\n  # The class may have been declared with namespace or classname qualifiers.\n  # The constructor and destructor will not have those qualifiers.\n  base_classname = classinfo.name.split('::')[-1]\n\n  # Look for single-argument constructors that aren't marked explicit.\n  # Technically a valid construct, but against style.\n  args = Match(r'\\s+(?:inline\\s+)?%s\\s*\\(([^,()]+)\\)'\n               % re.escape(base_classname),\n               line)\n  if (args and\n      args.group(1) != 'void' and\n      not Match(r'(const\\s+)?%s\\s*(?:<\\w+>\\s*)?&' % re.escape(base_classname),\n                args.group(1).strip())):\n    error(filename, linenum, 'runtime/explicit', 5,\n          'Single-argument constructors should be marked explicit.')\n\n  # Look for methods declared virtual.\n  if Search(r'\\bvirtual\\b', line):\n    classinfo.virtual_method_linenumber = linenum\n    # Only look for a destructor declaration on the same line. It would\n    # be extremely unlikely for the destructor declaration to occupy\n    # more than one line.\n    if Search(r'~%s\\s*\\(' % base_classname, line):\n      classinfo.has_virtual_destructor = True\n\n  # Look for class end.\n  brace_depth = classinfo.brace_depth\n  brace_depth = brace_depth + line.count('{') - line.count('}')\n  if brace_depth <= 0:\n    classinfo = classinfo_stack.pop()\n    # Try to detect missing virtual destructor declarations.\n    # For now, only warn if a non-derived class with virtual methods lacks\n    # a virtual destructor. This is to make it less likely that people will\n    # declare derived virtual destructors without declaring the base\n    # destructor virtual.\n    if ((classinfo.virtual_method_linenumber is not None) and\n        (not classinfo.has_virtual_destructor) and\n        (not classinfo.is_derived)):  # Only warn for base classes\n      error(filename, classinfo.linenum, 'runtime/virtual', 4,\n            'The class %s probably needs a virtual destructor due to '\n            'having virtual method(s), one declared at line %d.'\n            % (classinfo.name, classinfo.virtual_method_linenumber))\n  else:\n    classinfo.brace_depth = brace_depth\n\n\ndef CheckSpacingForFunctionCall(filename, line, linenum, error):\n  \"\"\"Checks for the correctness of various spacing around function calls.\n\n  Args:\n    filename: The name of the current file.\n    line: The text of the line to check.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n\n  # Since function calls often occur inside if/for/while/switch\n  # expressions - which have their own, more liberal conventions - we\n  # first see if we should be looking inside such an expression for a\n  # function call, to which we can apply more strict standards.\n  fncall = line    # if there's no control flow construct, look at whole line\n  for pattern in (r'\\bif\\s*\\((.*)\\)\\s*{',\n                  r'\\bfor\\s*\\((.*)\\)\\s*{',\n                  r'\\bwhile\\s*\\((.*)\\)\\s*[{;]',\n                  r'\\bswitch\\s*\\((.*)\\)\\s*{'):\n    match = Search(pattern, line)\n    if match:\n      fncall = match.group(1)    # look inside the parens for function calls\n      break\n\n  # Except in if/for/while/switch, there should never be space\n  # immediately inside parens (eg \"f( 3, 4 )\").  We make an exception\n  # for nested parens ( (a+b) + c ).  Likewise, there should never be\n  # a space before a ( when it's a function argument.  I assume it's a\n  # function argument when the char before the whitespace is legal in\n  # a function name (alnum + _) and we're not starting a macro. Also ignore\n  # pointers and references to arrays and functions coz they're too tricky:\n  # we use a very simple way to recognize these:\n  # \" (something)(maybe-something)\" or\n  # \" (something)(maybe-something,\" or\n  # \" (something)[something]\"\n  # Note that we assume the contents of [] to be short enough that\n  # they'll never need to wrap.\n  if (  # Ignore control structures.\n      not Search(r'\\b(if|for|while|switch|return|delete)\\b', fncall) and\n      # Ignore pointers/references to functions.\n      not Search(r' \\([^)]+\\)\\([^)]*(\\)|,$)', fncall) and\n      # Ignore pointers/references to arrays.\n      not Search(r' \\([^)]+\\)\\[[^\\]]+\\]', fncall)):\n    if Search(r'\\w\\s*\\(\\s(?!\\s*\\\\$)', fncall):      # a ( used for a fn call\n      error(filename, linenum, 'whitespace/parens', 4,\n            'Extra space after ( in function call')\n    elif Search(r'\\(\\s+(?!(\\s*\\\\)|\\()', fncall):\n      error(filename, linenum, 'whitespace/parens', 2,\n            'Extra space after (')\n    if (Search(r'\\w\\s+\\(', fncall) and\n        not Search(r'#\\s*define|typedef', fncall)):\n      error(filename, linenum, 'whitespace/parens', 4,\n            'Extra space before ( in function call')\n    # If the ) is followed only by a newline or a { + newline, assume it's\n    # part of a control statement (if/while/etc), and don't complain\n    if Search(r'[^)]\\s+\\)\\s*[^{\\s]', fncall):\n      # If the closing parenthesis is preceded by only whitespaces,\n      # try to give a more descriptive error message.\n      if Search(r'^\\s+\\)', fncall):\n        error(filename, linenum, 'whitespace/parens', 2,\n              'Closing ) should be moved to the previous line')\n      else:\n        error(filename, linenum, 'whitespace/parens', 2,\n              'Extra space before )')\n\n\ndef IsBlankLine(line):\n  \"\"\"Returns true if the given line is blank.\n\n  We consider a line to be blank if the line is empty or consists of\n  only white spaces.\n\n  Args:\n    line: A line of a string.\n\n  Returns:\n    True, if the given line is blank.\n  \"\"\"\n  return not line or line.isspace()\n\n\ndef CheckForFunctionLengths(filename, clean_lines, linenum,\n                            function_state, error):\n  \"\"\"Reports for long function bodies.\n\n  For an overview why this is done, see:\n  http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions\n\n  Uses a simplistic algorithm assuming other style guidelines\n  (especially spacing) are followed.\n  Only checks unindented functions, so class members are unchecked.\n  Trivial bodies are unchecked, so constructors with huge initializer lists\n  may be missed.\n  Blank/comment lines are not counted so as to avoid encouraging the removal\n  of vertical space and comments just to get through a lint check.\n  NOLINT *on the last line of a function* disables this check.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    function_state: Current function name and lines in body so far.\n    error: The function to call with any errors found.\n  \"\"\"\n  lines = clean_lines.lines\n  line = lines[linenum]\n  raw = clean_lines.raw_lines\n  raw_line = raw[linenum]\n  joined_line = ''\n\n  starting_func = False\n  regexp = r'(\\w(\\w|::|\\*|\\&|\\s)*)\\('  # decls * & space::name( ...\n  match_result = Match(regexp, line)\n  if match_result:\n    # If the name is all caps and underscores, figure it's a macro and\n    # ignore it, unless it's TEST or TEST_F.\n    function_name = match_result.group(1).split()[-1]\n    if function_name == 'TEST' or function_name == 'TEST_F' or (\n        not Match(r'[A-Z_]+$', function_name)):\n      starting_func = True\n\n  if starting_func:\n    body_found = False\n    for start_linenum in range(linenum, clean_lines.NumLines()):\n      start_line = lines[start_linenum]\n      joined_line += ' ' + start_line.lstrip()\n      if Search(r'(;|})', start_line):  # Declarations and trivial functions\n        body_found = True\n        break                              # ... ignore\n      elif Search(r'{', start_line):\n        body_found = True\n        function = Search(r'((\\w|:)*)\\(', line).group(1)\n        if Match(r'TEST', function):    # Handle TEST... macros\n          parameter_regexp = Search(r'(\\(.*\\))', joined_line)\n          if parameter_regexp:             # Ignore bad syntax\n            function += parameter_regexp.group(1)\n        else:\n          function += '()'\n        function_state.Begin(function)\n        break\n    if not body_found:\n      # No body for the function (or evidence of a non-function) was found.\n      error(filename, linenum, 'readability/fn_size', 5,\n            'Lint failed to find start of function body.')\n  elif Match(r'^\\}\\s*$', line):  # function end\n    function_state.Check(error, filename, linenum)\n    function_state.End()\n  elif not Match(r'^\\s*$', line):\n    function_state.Count()  # Count non-blank/non-comment lines.\n\n\n_RE_PATTERN_TODO = re.compile(r'^//(\\s*)TODO(\\(.+?\\))?:?(\\s|$)?')\n\n\ndef CheckComment(comment, filename, linenum, error):\n  \"\"\"Checks for common mistakes in TODO comments.\n\n  Args:\n    comment: The text of the comment from the line in question.\n    filename: The name of the current file.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n  match = _RE_PATTERN_TODO.match(comment)\n  if match:\n    # One whitespace is correct; zero whitespace is handled elsewhere.\n    leading_whitespace = match.group(1)\n    if len(leading_whitespace) > 1:\n      error(filename, linenum, 'whitespace/todo', 2,\n            'Too many spaces before TODO')\n\n    username = match.group(2)\n    if not username:\n      error(filename, linenum, 'readability/todo', 2,\n            'Missing username in TODO; it should look like '\n            '\"// TODO(my_username): Stuff.\"')\n\n    middle_whitespace = match.group(3)\n    # Comparisons made explicit for correctness -- pylint: disable-msg=C6403\n    if middle_whitespace != ' ' and middle_whitespace != '':\n      error(filename, linenum, 'whitespace/todo', 2,\n            'TODO(my_username) should be followed by a space')\n\n\ndef CheckSpacing(filename, clean_lines, linenum, error):\n  \"\"\"Checks for the correctness of various spacing issues in the code.\n\n  Things we check for: spaces around operators, spaces after\n  if/for/while/switch, no spaces around parens in function calls, two\n  spaces between code and comment, don't start a block with a blank\n  line, don't end a function with a blank line, don't add a blank line\n  after public/protected/private, don't have too many blank lines in a row.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n\n  raw = clean_lines.raw_lines\n  line = raw[linenum]\n\n  # Before nixing comments, check if the line is blank for no good\n  # reason.  This includes the first line after a block is opened, and\n  # blank lines at the end of a function (ie, right before a line like '}'\n  if IsBlankLine(line):\n    elided = clean_lines.elided\n    prev_line = elided[linenum - 1]\n    prevbrace = prev_line.rfind('{')\n    # TODO(unknown): Don't complain if line before blank line, and line after,\n    #                both start with alnums and are indented the same amount.\n    #                This ignores whitespace at the start of a namespace block\n    #                because those are not usually indented.\n    if (prevbrace != -1 and prev_line[prevbrace:].find('}') == -1\n        and prev_line[:prevbrace].find('namespace') == -1):\n      # OK, we have a blank line at the start of a code block.  Before we\n      # complain, we check if it is an exception to the rule: The previous\n      # non-empty line has the parameters of a function header that are indented\n      # 4 spaces (because they did not fit in a 80 column line when placed on\n      # the same line as the function name).  We also check for the case where\n      # the previous line is indented 6 spaces, which may happen when the\n      # initializers of a constructor do not fit into a 80 column line.\n      exception = False\n      if Match(r' {6}\\w', prev_line):  # Initializer list?\n        # We are looking for the opening column of initializer list, which\n        # should be indented 4 spaces to cause 6 space indentation afterwards.\n        search_position = linenum-2\n        while (search_position >= 0\n               and Match(r' {6}\\w', elided[search_position])):\n          search_position -= 1\n        exception = (search_position >= 0\n                     and elided[search_position][:5] == '    :')\n      else:\n        # Search for the function arguments or an initializer list.  We use a\n        # simple heuristic here: If the line is indented 4 spaces; and we have a\n        # closing paren, without the opening paren, followed by an opening brace\n        # or colon (for initializer lists) we assume that it is the last line of\n        # a function header.  If we have a colon indented 4 spaces, it is an\n        # initializer list.\n        exception = (Match(r' {4}\\w[^\\(]*\\)\\s*(const\\s*)?(\\{\\s*$|:)',\n                           prev_line)\n                     or Match(r' {4}:', prev_line))\n\n      if not exception:\n        error(filename, linenum, 'whitespace/blank_line', 2,\n              'Blank line at the start of a code block.  Is this needed?')\n    # This doesn't ignore whitespace at the end of a namespace block\n    # because that is too hard without pairing open/close braces;\n    # however, a special exception is made for namespace closing\n    # brackets which have a comment containing \"namespace\".\n    #\n    # Also, ignore blank lines at the end of a block in a long if-else\n    # chain, like this:\n    #   if (condition1) {\n    #     // Something followed by a blank line\n    #\n    #   } else if (condition2) {\n    #     // Something else\n    #   }\n    if linenum + 1 < clean_lines.NumLines():\n      next_line = raw[linenum + 1]\n      if (next_line\n          and Match(r'\\s*}', next_line)\n          and next_line.find('namespace') == -1\n          and next_line.find('} else ') == -1):\n        error(filename, linenum, 'whitespace/blank_line', 3,\n              'Blank line at the end of a code block.  Is this needed?')\n\n    matched = Match(r'\\s*(public|protected|private):', prev_line)\n    if matched:\n      error(filename, linenum, 'whitespace/blank_line', 3,\n            'Do not leave a blank line after \"%s:\"' % matched.group(1))\n\n  # Next, we complain if there's a comment too near the text\n  commentpos = line.find('//')\n  if commentpos != -1:\n    # Check if the // may be in quotes.  If so, ignore it\n    # Comparisons made explicit for clarity -- pylint: disable-msg=C6403\n    if (line.count('\"', 0, commentpos) -\n        line.count('\\\\\"', 0, commentpos)) % 2 == 0:   # not in quotes\n      # Allow one space for new scopes, two spaces otherwise:\n      if (not Match(r'^\\s*{ //', line) and\n          ((commentpos >= 1 and\n            line[commentpos-1] not in string.whitespace) or\n           (commentpos >= 2 and\n            line[commentpos-2] not in string.whitespace))):\n        error(filename, linenum, 'whitespace/comments', 2,\n              'At least two spaces is best between code and comments')\n      # There should always be a space between the // and the comment\n      commentend = commentpos + 2\n      if commentend < len(line) and not line[commentend] == ' ':\n        # but some lines are exceptions -- e.g. if they're big\n        # comment delimiters like:\n        # //----------------------------------------------------------\n        # or are an empty C++ style Doxygen comment, like:\n        # ///\n        # or they begin with multiple slashes followed by a space:\n        # //////// Header comment\n        match = (Search(r'[=/-]{4,}\\s*$', line[commentend:]) or\n                 Search(r'^/$', line[commentend:]) or\n                 Search(r'^/+ ', line[commentend:]))\n        if not match:\n          error(filename, linenum, 'whitespace/comments', 4,\n                'Should have a space between // and comment')\n      CheckComment(line[commentpos:], filename, linenum, error)\n\n  line = clean_lines.elided[linenum]  # get rid of comments and strings\n\n  # Don't try to do spacing checks for operator methods\n  line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\\(', 'operator\\(', line)\n\n  # We allow no-spaces around = within an if: \"if ( (a=Foo()) == 0 )\".\n  # Otherwise not.  Note we only check for non-spaces on *both* sides;\n  # sometimes people put non-spaces on one side when aligning ='s among\n  # many lines (not that this is behavior that I approve of...)\n  if Search(r'[\\w.]=[\\w.]', line) and not Search(r'\\b(if|while) ', line):\n    error(filename, linenum, 'whitespace/operators', 4,\n          'Missing spaces around =')\n\n  # It's ok not to have spaces around binary operators like + - * /, but if\n  # there's too little whitespace, we get concerned.  It's hard to tell,\n  # though, so we punt on this one for now.  TODO.\n\n  # You should always have whitespace around binary operators.\n  # Alas, we can't test < or > because they're legitimately used sans spaces\n  # (a->b, vector<int> a).  The only time we can tell is a < with no >, and\n  # only if it's not template params list spilling into the next line.\n  match = Search(r'[^<>=!\\s](==|!=|<=|>=)[^<>=!\\s]', line)\n  if not match:\n    # Note that while it seems that the '<[^<]*' term in the following\n    # regexp could be simplified to '<.*', which would indeed match\n    # the same class of strings, the [^<] means that searching for the\n    # regexp takes linear rather than quadratic time.\n    if not Search(r'<[^<]*,\\s*$', line):  # template params spill\n      match = Search(r'[^<>=!\\s](<)[^<>=!\\s]([^>]|->)*$', line)\n  if match:\n    error(filename, linenum, 'whitespace/operators', 3,\n          'Missing spaces around %s' % match.group(1))\n  # We allow no-spaces around << and >> when used like this: 10<<20, but\n  # not otherwise (particularly, not when used as streams)\n  match = Search(r'[^0-9\\s](<<|>>)[^0-9\\s]', line)\n  if match:\n    error(filename, linenum, 'whitespace/operators', 3,\n          'Missing spaces around %s' % match.group(1))\n\n  # There shouldn't be space around unary operators\n  match = Search(r'(!\\s|~\\s|[\\s]--[\\s;]|[\\s]\\+\\+[\\s;])', line)\n  if match:\n    error(filename, linenum, 'whitespace/operators', 4,\n          'Extra space for operator %s' % match.group(1))\n\n  # A pet peeve of mine: no spaces after an if, while, switch, or for\n  match = Search(r' (if\\(|for\\(|while\\(|switch\\()', line)\n  if match:\n    error(filename, linenum, 'whitespace/parens', 5,\n          'Missing space before ( in %s' % match.group(1))\n\n  # For if/for/while/switch, the left and right parens should be\n  # consistent about how many spaces are inside the parens, and\n  # there should either be zero or one spaces inside the parens.\n  # We don't want: \"if ( foo)\" or \"if ( foo   )\".\n  # Exception: \"for ( ; foo; bar)\" and \"for (foo; bar; )\" are allowed.\n  match = Search(r'\\b(if|for|while|switch)\\s*'\n                 r'\\(([ ]*)(.).*[^ ]+([ ]*)\\)\\s*{\\s*$',\n                 line)\n  if match:\n    if len(match.group(2)) != len(match.group(4)):\n      if not (match.group(3) == ';' and\n              len(match.group(2)) == 1 + len(match.group(4)) or\n              not match.group(2) and Search(r'\\bfor\\s*\\(.*; \\)', line)):\n        error(filename, linenum, 'whitespace/parens', 5,\n              'Mismatching spaces inside () in %s' % match.group(1))\n    if not len(match.group(2)) in [0, 1]:\n      error(filename, linenum, 'whitespace/parens', 5,\n            'Should have zero or one spaces inside ( and ) in %s' %\n            match.group(1))\n\n  # You should always have a space after a comma (either as fn arg or operator)\n  if Search(r',[^\\s]', line):\n    error(filename, linenum, 'whitespace/comma', 3,\n          'Missing space after ,')\n\n  # You should always have a space after a semicolon\n  # except for few corner cases\n  # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more\n  # space after ;\n  if Search(r';[^\\s};\\\\)/]', line):\n    error(filename, linenum, 'whitespace/semicolon', 3,\n          'Missing space after ;')\n\n  # Next we will look for issues with function calls.\n  CheckSpacingForFunctionCall(filename, line, linenum, error)\n\n  # Except after an opening paren, or after another opening brace (in case of\n  # an initializer list, for instance), you should have spaces before your\n  # braces. And since you should never have braces at the beginning of a line,\n  # this is an easy test.\n  if Search(r'[^ ({]{', line):\n    error(filename, linenum, 'whitespace/braces', 5,\n          'Missing space before {')\n\n  # Make sure '} else {' has spaces.\n  if Search(r'}else', line):\n    error(filename, linenum, 'whitespace/braces', 5,\n          'Missing space before else')\n\n  # You shouldn't have spaces before your brackets, except maybe after\n  # 'delete []' or 'new char * []'.\n  if Search(r'\\w\\s+\\[', line) and not Search(r'delete\\s+\\[', line):\n    error(filename, linenum, 'whitespace/braces', 5,\n          'Extra space before [')\n\n  # You shouldn't have a space before a semicolon at the end of the line.\n  # There's a special case for \"for\" since the style guide allows space before\n  # the semicolon there.\n  if Search(r':\\s*;\\s*$', line):\n    error(filename, linenum, 'whitespace/semicolon', 5,\n          'Semicolon defining empty statement. Use { } instead.')\n  elif Search(r'^\\s*;\\s*$', line):\n    error(filename, linenum, 'whitespace/semicolon', 5,\n          'Line contains only semicolon. If this should be an empty statement, '\n          'use { } instead.')\n  elif (Search(r'\\s+;\\s*$', line) and\n        not Search(r'\\bfor\\b', line)):\n    error(filename, linenum, 'whitespace/semicolon', 5,\n          'Extra space before last semicolon. If this should be an empty '\n          'statement, use { } instead.')\n\n\ndef CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):\n  \"\"\"Checks for additional blank line issues related to sections.\n\n  Currently the only thing checked here is blank line before protected/private.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    class_info: A _ClassInfo objects.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n  # Skip checks if the class is small, where small means 25 lines or less.\n  # 25 lines seems like a good cutoff since that's the usual height of\n  # terminals, and any class that can't fit in one screen can't really\n  # be considered \"small\".\n  #\n  # Also skip checks if we are on the first line.  This accounts for\n  # classes that look like\n  #   class Foo { public: ... };\n  #\n  # If we didn't find the end of the class, last_line would be zero,\n  # and the check will be skipped by the first condition.\n  if (class_info.last_line - class_info.linenum <= 24 or\n      linenum <= class_info.linenum):\n    return\n\n  matched = Match(r'\\s*(public|protected|private):', clean_lines.lines[linenum])\n  if matched:\n    # Issue warning if the line before public/protected/private was\n    # not a blank line, but don't do this if the previous line contains\n    # \"class\" or \"struct\".  This can happen two ways:\n    #  - We are at the beginning of the class.\n    #  - We are forward-declaring an inner class that is semantically\n    #    private, but needed to be public for implementation reasons.\n    prev_line = clean_lines.lines[linenum - 1]\n    if (not IsBlankLine(prev_line) and\n        not Search(r'\\b(class|struct)\\b', prev_line)):\n      # Try a bit harder to find the beginning of the class.  This is to\n      # account for multi-line base-specifier lists, e.g.:\n      #   class Derived\n      #       : public Base {\n      end_class_head = class_info.linenum\n      for i in range(class_info.linenum, linenum):\n        if Search(r'\\{\\s*$', clean_lines.lines[i]):\n          end_class_head = i\n          break\n      if end_class_head < linenum - 1:\n        error(filename, linenum, 'whitespace/blank_line', 3,\n              '\"%s:\" should be preceded by a blank line' % matched.group(1))\n\n\ndef GetPreviousNonBlankLine(clean_lines, linenum):\n  \"\"\"Return the most recent non-blank line and its line number.\n\n  Args:\n    clean_lines: A CleansedLines instance containing the file contents.\n    linenum: The number of the line to check.\n\n  Returns:\n    A tuple with two elements.  The first element is the contents of the last\n    non-blank line before the current line, or the empty string if this is the\n    first non-blank line.  The second is the line number of that line, or -1\n    if this is the first non-blank line.\n  \"\"\"\n\n  prevlinenum = linenum - 1\n  while prevlinenum >= 0:\n    prevline = clean_lines.elided[prevlinenum]\n    if not IsBlankLine(prevline):     # if not a blank line...\n      return (prevline, prevlinenum)\n    prevlinenum -= 1\n  return ('', -1)\n\n\ndef CheckBraces(filename, clean_lines, linenum, error):\n  \"\"\"Looks for misplaced braces (e.g. at the end of line).\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n\n  line = clean_lines.elided[linenum]        # get rid of comments and strings\n\n  if Match(r'\\s*{\\s*$', line):\n    # We allow an open brace to start a line in the case where someone\n    # is using braces in a block to explicitly create a new scope,\n    # which is commonly used to control the lifetime of\n    # stack-allocated variables.  We don't detect this perfectly: we\n    # just don't complain if the last non-whitespace character on the\n    # previous non-blank line is ';', ':', '{', or '}'.\n    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]\n    if not Search(r'[;:}{]\\s*$', prevline):\n      error(filename, linenum, 'whitespace/braces', 4,\n            '{ should almost always be at the end of the previous line')\n\n  # An else clause should be on the same line as the preceding closing brace.\n  if Match(r'\\s*else\\s*', line):\n    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]\n    if Match(r'\\s*}\\s*$', prevline):\n      error(filename, linenum, 'whitespace/newline', 4,\n            'An else should appear on the same line as the preceding }')\n\n  # If braces come on one side of an else, they should be on both.\n  # However, we have to worry about \"else if\" that spans multiple lines!\n  if Search(r'}\\s*else[^{]*$', line) or Match(r'[^}]*else\\s*{', line):\n    if Search(r'}\\s*else if([^{]*)$', line):       # could be multi-line if\n      # find the ( after the if\n      pos = line.find('else if')\n      pos = line.find('(', pos)\n      if pos > 0:\n        (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)\n        if endline[endpos:].find('{') == -1:    # must be brace after if\n          error(filename, linenum, 'readability/braces', 5,\n                'If an else has a brace on one side, it should have it on both')\n    else:            # common case: else not followed by a multi-line if\n      error(filename, linenum, 'readability/braces', 5,\n            'If an else has a brace on one side, it should have it on both')\n\n  # Likewise, an else should never have the else clause on the same line\n  if Search(r'\\belse [^\\s{]', line) and not Search(r'\\belse if\\b', line):\n    error(filename, linenum, 'whitespace/newline', 4,\n          'Else clause should never be on same line as else (use 2 lines)')\n\n  # In the same way, a do/while should never be on one line\n  if Match(r'\\s*do [^\\s{]', line):\n    error(filename, linenum, 'whitespace/newline', 4,\n          'do/while clauses should not be on a single line')\n\n  # Braces shouldn't be followed by a ; unless they're defining a struct\n  # or initializing an array.\n  # We can't tell in general, but we can for some common cases.\n  prevlinenum = linenum\n  while True:\n    (prevline, prevlinenum) = GetPreviousNonBlankLine(clean_lines, prevlinenum)\n    if Match(r'\\s+{.*}\\s*;', line) and not prevline.count(';'):\n      line = prevline + line\n    else:\n      break\n  if (Search(r'{.*}\\s*;', line) and\n      line.count('{') == line.count('}') and\n      not Search(r'struct|class|enum|\\s*=\\s*{', line)):\n    error(filename, linenum, 'readability/braces', 4,\n          \"You don't need a ; after a }\")\n\n\ndef ReplaceableCheck(operator, macro, line):\n  \"\"\"Determine whether a basic CHECK can be replaced with a more specific one.\n\n  For example suggest using CHECK_EQ instead of CHECK(a == b) and\n  similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.\n\n  Args:\n    operator: The C++ operator used in the CHECK.\n    macro: The CHECK or EXPECT macro being called.\n    line: The current source line.\n\n  Returns:\n    True if the CHECK can be replaced with a more specific one.\n  \"\"\"\n\n  # This matches decimal and hex integers, strings, and chars (in that order).\n  match_constant = r'([-+]?(\\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|\".*\"|\\'.*\\')'\n\n  # Expression to match two sides of the operator with something that\n  # looks like a literal, since CHECK(x == iterator) won't compile.\n  # This means we can't catch all the cases where a more specific\n  # CHECK is possible, but it's less annoying than dealing with\n  # extraneous warnings.\n  match_this = (r'\\s*' + macro + r'\\((\\s*' +\n                match_constant + r'\\s*' + operator + r'[^<>].*|'\n                r'.*[^<>]' + operator + r'\\s*' + match_constant +\n                r'\\s*\\))')\n\n  # Don't complain about CHECK(x == NULL) or similar because\n  # CHECK_EQ(x, NULL) won't compile (requires a cast).\n  # Also, don't complain about more complex boolean expressions\n  # involving && or || such as CHECK(a == b || c == d).\n  return Match(match_this, line) and not Search(r'NULL|&&|\\|\\|', line)\n\n\ndef CheckCheck(filename, clean_lines, linenum, error):\n  \"\"\"Checks the use of CHECK and EXPECT macros.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n\n  # Decide the set of replacement macros that should be suggested\n  raw_lines = clean_lines.raw_lines\n  current_macro = ''\n  for macro in _CHECK_MACROS:\n    if raw_lines[linenum].find(macro) >= 0:\n      current_macro = macro\n      break\n  if not current_macro:\n    # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT'\n    return\n\n  line = clean_lines.elided[linenum]        # get rid of comments and strings\n\n  # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc.\n  for operator in ['==', '!=', '>=', '>', '<=', '<']:\n    if ReplaceableCheck(operator, current_macro, line):\n      error(filename, linenum, 'readability/check', 2,\n            'Consider using %s instead of %s(a %s b)' % (\n                _CHECK_REPLACEMENT[current_macro][operator],\n                current_macro, operator))\n      break\n\n\ndef GetLineWidth(line):\n  \"\"\"Determines the width of the line in column positions.\n\n  Args:\n    line: A string, which may be a Unicode string.\n\n  Returns:\n    The width of the line in column positions, accounting for Unicode\n    combining characters and wide characters.\n  \"\"\"\n  if isinstance(line, TEXT_TYPE):\n    width = 0\n    for uc in unicodedata.normalize('NFC', line):\n      if unicodedata.east_asian_width(uc) in ('W', 'F'):\n        width += 2\n      elif not unicodedata.combining(uc):\n        width += 1\n    return width\n  else:\n    return len(line)\n\n\ndef CheckStyle(filename, clean_lines, linenum, file_extension, class_state,\n               error):\n  \"\"\"Checks rules from the 'C++ style rules' section of cppguide.html.\n\n  Most of these rules are hard to test (naming, comment style), but we\n  do what we can.  In particular we check for 2-space indents, line lengths,\n  tab usage, spaces inside code, etc.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    file_extension: The extension (without the dot) of the filename.\n    error: The function to call with any errors found.\n  \"\"\"\n\n  raw_lines = clean_lines.raw_lines\n  line = raw_lines[linenum]\n\n  if line.find('\\t') != -1:\n    error(filename, linenum, 'whitespace/tab', 1,\n          'Tab found; better to use spaces')\n\n  # One or three blank spaces at the beginning of the line is weird; it's\n  # hard to reconcile that with 2-space indents.\n  # NOTE: here are the conditions rob pike used for his tests.  Mine aren't\n  # as sophisticated, but it may be worth becoming so:  RLENGTH==initial_spaces\n  # if(RLENGTH > 20) complain = 0;\n  # if(match($0, \" +(error|private|public|protected):\")) complain = 0;\n  # if(match(prev, \"&& *$\")) complain = 0;\n  # if(match(prev, \"\\\\|\\\\| *$\")) complain = 0;\n  # if(match(prev, \"[\\\",=><] *$\")) complain = 0;\n  # if(match($0, \" <<\")) complain = 0;\n  # if(match(prev, \" +for \\\\(\")) complain = 0;\n  # if(prevodd && match(prevprev, \" +for \\\\(\")) complain = 0;\n  initial_spaces = 0\n  cleansed_line = clean_lines.elided[linenum]\n  while initial_spaces < len(line) and line[initial_spaces] == ' ':\n    initial_spaces += 1\n  if line and line[-1].isspace():\n    error(filename, linenum, 'whitespace/end_of_line', 4,\n          'Line ends in whitespace.  Consider deleting these extra spaces.')\n  # There are certain situations we allow one space, notably for labels\n  elif ((initial_spaces == 1 or initial_spaces == 3) and\n        not Match(r'\\s*\\w+\\s*:\\s*$', cleansed_line)):\n    error(filename, linenum, 'whitespace/indent', 3,\n          'Weird number of spaces at line-start.  '\n          'Are you using a 2-space indent?')\n  # Labels should always be indented at least one space.\n  elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\\s*$',\n                                                          line):\n    error(filename, linenum, 'whitespace/labels', 4,\n          'Labels should always be indented at least one space.  '\n          'If this is a member-initializer list in a constructor or '\n          'the base class list in a class definition, the colon should '\n          'be on the following line.')\n\n\n  # Check if the line is a header guard.\n  is_header_guard = False\n  if file_extension == 'h':\n    cppvar = GetHeaderGuardCPPVariable(filename)\n    if (line.startswith('#ifndef %s' % cppvar) or\n        line.startswith('#define %s' % cppvar) or\n        line.startswith('#endif  // %s' % cppvar)):\n      is_header_guard = True\n  # #include lines and header guards can be long, since there's no clean way to\n  # split them.\n  #\n  # URLs can be long too.  It's possible to split these, but it makes them\n  # harder to cut&paste.\n  #\n  # The \"$Id:...$\" comment may also get very long without it being the\n  # developers fault.\n  if (not line.startswith('#include') and not is_header_guard and\n      not Match(r'^\\s*//.*http(s?)://\\S*$', line) and\n      not Match(r'^// \\$Id:.*#[0-9]+ \\$$', line)):\n    line_width = GetLineWidth(line)\n    if line_width > 100:\n      error(filename, linenum, 'whitespace/line_length', 4,\n            'Lines should very rarely be longer than 100 characters')\n    elif line_width > 80:\n      error(filename, linenum, 'whitespace/line_length', 2,\n            'Lines should be <= 80 characters long')\n\n  if (cleansed_line.count(';') > 1 and\n      # for loops are allowed two ;'s (and may run over two lines).\n      cleansed_line.find('for') == -1 and\n      (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or\n       GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and\n      # It's ok to have many commands in a switch case that fits in 1 line\n      not ((cleansed_line.find('case ') != -1 or\n            cleansed_line.find('default:') != -1) and\n           cleansed_line.find('break;') != -1)):\n    error(filename, linenum, 'whitespace/newline', 4,\n          'More than one command on the same line')\n\n  # Some more style checks\n  CheckBraces(filename, clean_lines, linenum, error)\n  CheckSpacing(filename, clean_lines, linenum, error)\n  CheckCheck(filename, clean_lines, linenum, error)\n  if class_state and class_state.classinfo_stack:\n    CheckSectionSpacing(filename, clean_lines,\n                        class_state.classinfo_stack[-1], linenum, error)\n\n\n_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +\"[^/]+\\.h\"')\n_RE_PATTERN_INCLUDE = re.compile(r'^\\s*#\\s*include\\s*([<\"])([^>\"]*)[>\"].*$')\n# Matches the first component of a filename delimited by -s and _s. That is:\n#  _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'\n#  _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'\n#  _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'\n#  _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'\n_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')\n\n\ndef _DropCommonSuffixes(filename):\n  \"\"\"Drops common suffixes like _test.cc or -inl.h from filename.\n\n  For example:\n    >>> _DropCommonSuffixes('foo/foo-inl.h')\n    'foo/foo'\n    >>> _DropCommonSuffixes('foo/bar/foo.cc')\n    'foo/bar/foo'\n    >>> _DropCommonSuffixes('foo/foo_internal.h')\n    'foo/foo'\n    >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')\n    'foo/foo_unusualinternal'\n\n  Args:\n    filename: The input filename.\n\n  Returns:\n    The filename with the common suffix removed.\n  \"\"\"\n  for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',\n                 'inl.h', 'impl.h', 'internal.h'):\n    if (filename.endswith(suffix) and len(filename) > len(suffix) and\n        filename[-len(suffix) - 1] in ('-', '_')):\n      return filename[:-len(suffix) - 1]\n  return os.path.splitext(filename)[0]\n\n\ndef _IsTestFilename(filename):\n  \"\"\"Determines if the given filename has a suffix that identifies it as a test.\n\n  Args:\n    filename: The input filename.\n\n  Returns:\n    True if 'filename' looks like a test, False otherwise.\n  \"\"\"\n  if (filename.endswith('_test.cc') or\n      filename.endswith('_unittest.cc') or\n      filename.endswith('_regtest.cc')):\n    return True\n  else:\n    return False\n\n\ndef _ClassifyInclude(fileinfo, include, is_system):\n  \"\"\"Figures out what kind of header 'include' is.\n\n  Args:\n    fileinfo: The current file cpplint is running over. A FileInfo instance.\n    include: The path to a #included file.\n    is_system: True if the #include used <> rather than \"\".\n\n  Returns:\n    One of the _XXX_HEADER constants.\n\n  For example:\n    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)\n    _C_SYS_HEADER\n    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)\n    _CPP_SYS_HEADER\n    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)\n    _LIKELY_MY_HEADER\n    >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),\n    ...                  'bar/foo_other_ext.h', False)\n    _POSSIBLE_MY_HEADER\n    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)\n    _OTHER_HEADER\n  \"\"\"\n  # This is a list of all standard c++ header files, except\n  # those already checked for above.\n  is_stl_h = include in _STL_HEADERS\n  is_cpp_h = is_stl_h or include in _CPP_HEADERS\n\n  if is_system:\n    if is_cpp_h:\n      return _CPP_SYS_HEADER\n    else:\n      return _C_SYS_HEADER\n\n  # If the target file and the include we're checking share a\n  # basename when we drop common extensions, and the include\n  # lives in . , then it's likely to be owned by the target file.\n  target_dir, target_base = (\n      os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))\n  include_dir, include_base = os.path.split(_DropCommonSuffixes(include))\n  if target_base == include_base and (\n      include_dir == target_dir or\n      include_dir == os.path.normpath(target_dir + '/../public')):\n    return _LIKELY_MY_HEADER\n\n  # If the target and include share some initial basename\n  # component, it's possible the target is implementing the\n  # include, so it's allowed to be first, but we'll never\n  # complain if it's not there.\n  target_first_component = _RE_FIRST_COMPONENT.match(target_base)\n  include_first_component = _RE_FIRST_COMPONENT.match(include_base)\n  if (target_first_component and include_first_component and\n      target_first_component.group(0) ==\n      include_first_component.group(0)):\n    return _POSSIBLE_MY_HEADER\n\n  return _OTHER_HEADER\n\n\n\ndef CheckIncludeLine(filename, clean_lines, linenum, include_state, error):\n  \"\"\"Check rules that are applicable to #include lines.\n\n  Strings on #include lines are NOT removed from elided line, to make\n  certain tasks easier. However, to prevent false positives, checks\n  applicable to #include lines in CheckLanguage must be put here.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    include_state: An _IncludeState instance in which the headers are inserted.\n    error: The function to call with any errors found.\n  \"\"\"\n  fileinfo = FileInfo(filename)\n\n  line = clean_lines.lines[linenum]\n\n  # \"include\" should use the new style \"foo/bar.h\" instead of just \"bar.h\"\n  if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line):\n    error(filename, linenum, 'build/include', 4,\n          'Include the directory when naming .h files')\n\n  # we shouldn't include a file more than once. actually, there are a\n  # handful of instances where doing so is okay, but in general it's\n  # not.\n  match = _RE_PATTERN_INCLUDE.search(line)\n  if match:\n    include = match.group(2)\n    is_system = (match.group(1) == '<')\n    if include in include_state:\n      error(filename, linenum, 'build/include', 4,\n            '\"%s\" already included at %s:%s' %\n            (include, filename, include_state[include]))\n    else:\n      include_state[include] = linenum\n\n      # We want to ensure that headers appear in the right order:\n      # 1) for foo.cc, foo.h  (preferred location)\n      # 2) c system files\n      # 3) cpp system files\n      # 4) for foo.cc, foo.h  (deprecated location)\n      # 5) other google headers\n      #\n      # We classify each include statement as one of those 5 types\n      # using a number of techniques. The include_state object keeps\n      # track of the highest type seen, and complains if we see a\n      # lower type after that.\n      error_message = include_state.CheckNextIncludeOrder(\n          _ClassifyInclude(fileinfo, include, is_system))\n      if error_message:\n        error(filename, linenum, 'build/include_order', 4,\n              '%s. Should be: %s.h, c system, c++ system, other.' %\n              (error_message, fileinfo.BaseName()))\n      if not include_state.IsInAlphabeticalOrder(include):\n        error(filename, linenum, 'build/include_alpha', 4,\n              'Include \"%s\" not in alphabetical order' % include)\n\n  # Look for any of the stream classes that are part of standard C++.\n  match = _RE_PATTERN_INCLUDE.match(line)\n  if match:\n    include = match.group(2)\n    if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):\n      # Many unit tests use cout, so we exempt them.\n      if not _IsTestFilename(filename):\n        error(filename, linenum, 'readability/streams', 3,\n              'Streams are highly discouraged.')\n\n\ndef _GetTextInside(text, start_pattern):\n  \"\"\"Retrieves all the text between matching open and close parentheses.\n\n  Given a string of lines and a regular expression string, retrieve all the text\n  following the expression and between opening punctuation symbols like\n  (, [, or {, and the matching close-punctuation symbol. This properly nested\n  occurrences of the punctuations, so for the text like\n    printf(a(), b(c()));\n  a call to _GetTextInside(text, r'printf\\(') will return 'a(), b(c())'.\n  start_pattern must match string having an open punctuation symbol at the end.\n\n  Args:\n    text: The lines to extract text. Its comments and strings must be elided.\n           It can be single line and can span multiple lines.\n    start_pattern: The regexp string indicating where to start extracting\n                   the text.\n  Returns:\n    The extracted text.\n    None if either the opening string or ending punctuation could not be found.\n  \"\"\"\n  # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably\n  # rewritten to use _GetTextInside (and use inferior regexp matching today).\n\n  # Give opening punctuations to get the matching close-punctuations.\n  matching_punctuation = {'(': ')', '{': '}', '[': ']'}\n  closing_punctuation = set(itervalues(matching_punctuation))\n\n  # Find the position to start extracting text.\n  match = re.search(start_pattern, text, re.M)\n  if not match:  # start_pattern not found in text.\n    return None\n  start_position = match.end(0)\n\n  assert start_position > 0, (\n      'start_pattern must ends with an opening punctuation.')\n  assert text[start_position - 1] in matching_punctuation, (\n      'start_pattern must ends with an opening punctuation.')\n  # Stack of closing punctuations we expect to have in text after position.\n  punctuation_stack = [matching_punctuation[text[start_position - 1]]]\n  position = start_position\n  while punctuation_stack and position < len(text):\n    if text[position] == punctuation_stack[-1]:\n      punctuation_stack.pop()\n    elif text[position] in closing_punctuation:\n      # A closing punctuation without matching opening punctuations.\n      return None\n    elif text[position] in matching_punctuation:\n      punctuation_stack.append(matching_punctuation[text[position]])\n    position += 1\n  if punctuation_stack:\n    # Opening punctuations left without matching close-punctuations.\n    return None\n  # punctuations match.\n  return text[start_position:position - 1]\n\n\ndef CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,\n                  error):\n  \"\"\"Checks rules from the 'C++ language rules' section of cppguide.html.\n\n  Some of these rules are hard to test (function overloading, using\n  uint32 inappropriately), but we do the best we can.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    file_extension: The extension (without the dot) of the filename.\n    include_state: An _IncludeState instance in which the headers are inserted.\n    error: The function to call with any errors found.\n  \"\"\"\n  # If the line is empty or consists of entirely a comment, no need to\n  # check it.\n  line = clean_lines.elided[linenum]\n  if not line:\n    return\n\n  match = _RE_PATTERN_INCLUDE.search(line)\n  if match:\n    CheckIncludeLine(filename, clean_lines, linenum, include_state, error)\n    return\n\n  # Create an extended_line, which is the concatenation of the current and\n  # next lines, for more effective checking of code that may span more than one\n  # line.\n  if linenum + 1 < clean_lines.NumLines():\n    extended_line = line + clean_lines.elided[linenum + 1]\n  else:\n    extended_line = line\n\n  # Make Windows paths like Unix.\n  fullname = os.path.abspath(filename).replace('\\\\', '/')\n\n  # TODO(unknown): figure out if they're using default arguments in fn proto.\n\n  # Check for non-const references in functions.  This is tricky because &\n  # is also used to take the address of something.  We allow <> for templates,\n  # (ignoring whatever is between the braces) and : for classes.\n  # These are complicated re's.  They try to capture the following:\n  # paren (for fn-prototype start), typename, &, varname.  For the const\n  # version, we're willing for const to be before typename or after\n  # Don't check the implementation on same line.\n  fnline = line.split('{', 1)[0]\n  if (len(re.findall(r'\\([^()]*\\b(?:[\\w:]|<[^()]*>)+(\\s?&|&\\s?)\\w+', fnline)) >\n      len(re.findall(r'\\([^()]*\\bconst\\s+(?:typename\\s+)?(?:struct\\s+)?'\n                     r'(?:[\\w:]|<[^()]*>)+(\\s?&|&\\s?)\\w+', fnline)) +\n      len(re.findall(r'\\([^()]*\\b(?:[\\w:]|<[^()]*>)+\\s+const(\\s?&|&\\s?)[\\w]+',\n                     fnline))):\n\n    # We allow non-const references in a few standard places, like functions\n    # called \"swap()\" or iostream operators like \"<<\" or \">>\".\n    if not Search(\n        r'(swap|Swap|operator[<>][<>])\\s*\\(\\s*(?:[\\w:]|<.*>)+\\s*&',\n        fnline):\n      error(filename, linenum, 'runtime/references', 2,\n            'Is this a non-const reference? '\n            'If so, make const or use a pointer.')\n\n  # Check to see if they're using an conversion function cast.\n  # I just try to capture the most common basic types, though there are more.\n  # Parameterless conversion functions, such as bool(), are allowed as they are\n  # probably a member operator declaration or default constructor.\n  match = Search(\n      r'(\\bnew\\s+)?\\b'  # Grab 'new' operator, if it's there\n      r'(int|float|double|bool|char|int32|uint32|int64|uint64)\\([^)]', line)\n  if match:\n    # gMock methods are defined using some variant of MOCK_METHODx(name, type)\n    # where type may be float(), int(string), etc.  Without context they are\n    # virtually indistinguishable from int(x) casts. Likewise, gMock's\n    # MockCallback takes a template parameter of the form return_type(arg_type),\n    # which looks much like the cast we're trying to detect.\n    if (match.group(1) is None and  # If new operator, then this isn't a cast\n        not (Match(r'^\\s*MOCK_(CONST_)?METHOD\\d+(_T)?\\(', line) or\n             Match(r'^\\s*MockCallback<.*>', line))):\n      error(filename, linenum, 'readability/casting', 4,\n            'Using deprecated casting style.  '\n            'Use static_cast<%s>(...) instead' %\n            match.group(2))\n\n  CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],\n                  'static_cast',\n                  r'\\((int|float|double|bool|char|u?int(16|32|64))\\)', error)\n\n  # This doesn't catch all cases. Consider (const char * const)\"hello\".\n  #\n  # (char *) \"foo\" should always be a const_cast (reinterpret_cast won't\n  # compile).\n  if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],\n                     'const_cast', r'\\((char\\s?\\*+\\s?)\\)\\s*\"', error):\n    pass\n  else:\n    # Check pointer casts for other than string constants\n    CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],\n                    'reinterpret_cast', r'\\((\\w+\\s?\\*+\\s?)\\)', error)\n\n  # In addition, we look for people taking the address of a cast.  This\n  # is dangerous -- casts can assign to temporaries, so the pointer doesn't\n  # point where you think.\n  if Search(\n      r'(&\\([^)]+\\)[\\w(])|(&(static|dynamic|reinterpret)_cast\\b)', line):\n    error(filename, linenum, 'runtime/casting', 4,\n          ('Are you taking an address of a cast?  '\n           'This is dangerous: could be a temp var.  '\n           'Take the address before doing the cast, rather than after'))\n\n  # Check for people declaring static/global STL strings at the top level.\n  # This is dangerous because the C++ language does not guarantee that\n  # globals with constructors are initialized before the first access.\n  match = Match(\n      r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\\b(.*)',\n      line)\n  # Make sure it's not a function.\n  # Function template specialization looks like: \"string foo<Type>(...\".\n  # Class template definitions look like: \"string Foo<Type>::Method(...\".\n  if match and not Match(r'\\s*(<.*>)?(::[a-zA-Z0-9_]+)?\\s*\\(([^\"]|$)',\n                         match.group(3)):\n    error(filename, linenum, 'runtime/string', 4,\n          'For a static/global string constant, use a C style string instead: '\n          '\"%schar %s[]\".' %\n          (match.group(1), match.group(2)))\n\n  # Check that we're not using RTTI outside of testing code.\n  if Search(r'\\bdynamic_cast<', line) and not _IsTestFilename(filename):\n    error(filename, linenum, 'runtime/rtti', 5,\n          'Do not use dynamic_cast<>.  If you need to cast within a class '\n          \"hierarchy, use static_cast<> to upcast.  Google doesn't support \"\n          'RTTI.')\n\n  if Search(r'\\b([A-Za-z0-9_]*_)\\(\\1\\)', line):\n    error(filename, linenum, 'runtime/init', 4,\n          'You seem to be initializing a member variable with itself.')\n\n  if file_extension == 'h':\n    # TODO(unknown): check that 1-arg constructors are explicit.\n    #                How to tell it's a constructor?\n    #                (handled in CheckForNonStandardConstructs for now)\n    # TODO(unknown): check that classes have DISALLOW_EVIL_CONSTRUCTORS\n    #                (level 1 error)\n    pass\n\n  # Check if people are using the verboten C basic types.  The only exception\n  # we regularly allow is \"unsigned short port\" for port.\n  if Search(r'\\bshort port\\b', line):\n    if not Search(r'\\bunsigned short port\\b', line):\n      error(filename, linenum, 'runtime/int', 4,\n            'Use \"unsigned short\" for ports, not \"short\"')\n  else:\n    match = Search(r'\\b(short|long(?! +double)|long long)\\b', line)\n    if match:\n      error(filename, linenum, 'runtime/int', 4,\n            'Use int16/int64/etc, rather than the C type %s' % match.group(1))\n\n  # When snprintf is used, the second argument shouldn't be a literal.\n  match = Search(r'snprintf\\s*\\(([^,]*),\\s*([0-9]*)\\s*,', line)\n  if match and match.group(2) != '0':\n    # If 2nd arg is zero, snprintf is used to calculate size.\n    error(filename, linenum, 'runtime/printf', 3,\n          'If you can, use sizeof(%s) instead of %s as the 2nd arg '\n          'to snprintf.' % (match.group(1), match.group(2)))\n\n  # Check if some verboten C functions are being used.\n  if Search(r'\\bsprintf\\b', line):\n    error(filename, linenum, 'runtime/printf', 5,\n          'Never use sprintf.  Use snprintf instead.')\n  match = Search(r'\\b(strcpy|strcat)\\b', line)\n  if match:\n    error(filename, linenum, 'runtime/printf', 4,\n          'Almost always, snprintf is better than %s' % match.group(1))\n\n  if Search(r'\\bsscanf\\b', line):\n    error(filename, linenum, 'runtime/printf', 1,\n          'sscanf can be ok, but is slow and can overflow buffers.')\n\n  # Check if some verboten operator overloading is going on\n  # TODO(unknown): catch out-of-line unary operator&:\n  #   class X {};\n  #   int operator&(const X& x) { return 42; }  // unary operator&\n  # The trick is it's hard to tell apart from binary operator&:\n  #   class Y { int operator&(const Y& x) { return 23; } }; // binary operator&\n  if Search(r'\\boperator\\s*&\\s*\\(\\s*\\)', line):\n    error(filename, linenum, 'runtime/operator', 4,\n          'Unary operator& is dangerous.  Do not use it.')\n\n  # Check for suspicious usage of \"if\" like\n  # } if (a == b) {\n  if Search(r'\\}\\s*if\\s*\\(', line):\n    error(filename, linenum, 'readability/braces', 4,\n          'Did you mean \"else if\"? If not, start a new line for \"if\".')\n\n  # Check for potential format string bugs like printf(foo).\n  # We constrain the pattern not to pick things like DocidForPrintf(foo).\n  # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())\n  # TODO(sugawarayu): Catch the following case. Need to change the calling\n  # convention of the whole function to process multiple line to handle it.\n  #   printf(\n  #       boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);\n  printf_args = _GetTextInside(line, r'(?i)\\b(string)?printf\\s*\\(')\n  if printf_args:\n    match = Match(r'([\\w.\\->()]+)$', printf_args)\n    if match:\n      function_name = re.search(r'\\b((?:string)?printf)\\s*\\(',\n                                line, re.I).group(1)\n      error(filename, linenum, 'runtime/printf', 4,\n            'Potential format string bug. Do %s(\"%%s\", %s) instead.'\n            % (function_name, match.group(1)))\n\n  # Check for potential memset bugs like memset(buf, sizeof(buf), 0).\n  match = Search(r'memset\\s*\\(([^,]*),\\s*([^,]*),\\s*0\\s*\\)', line)\n  if match and not Match(r\"^''|-?[0-9]+|0x[0-9A-Fa-f]$\", match.group(2)):\n    error(filename, linenum, 'runtime/memset', 4,\n          'Did you mean \"memset(%s, 0, %s)\"?'\n          % (match.group(1), match.group(2)))\n\n  if Search(r'\\busing namespace\\b', line):\n    error(filename, linenum, 'build/namespaces', 5,\n          'Do not use namespace using-directives.  '\n          'Use using-declarations instead.')\n\n  # Detect variable-length arrays.\n  match = Match(r'\\s*(.+::)?(\\w+) [a-z]\\w*\\[(.+)];', line)\n  if (match and match.group(2) != 'return' and match.group(2) != 'delete' and\n      match.group(3).find(']') == -1):\n    # Split the size using space and arithmetic operators as delimiters.\n    # If any of the resulting tokens are not compile time constants then\n    # report the error.\n    tokens = re.split(r'\\s|\\+|\\-|\\*|\\/|<<|>>]', match.group(3))\n    is_const = True\n    skip_next = False\n    for tok in tokens:\n      if skip_next:\n        skip_next = False\n        continue\n\n      if Search(r'sizeof\\(.+\\)', tok): continue\n      if Search(r'arraysize\\(\\w+\\)', tok): continue\n\n      tok = tok.lstrip('(')\n      tok = tok.rstrip(')')\n      if not tok: continue\n      if Match(r'\\d+', tok): continue\n      if Match(r'0[xX][0-9a-fA-F]+', tok): continue\n      if Match(r'k[A-Z0-9]\\w*', tok): continue\n      if Match(r'(.+::)?k[A-Z0-9]\\w*', tok): continue\n      if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue\n      # A catch all for tricky sizeof cases, including 'sizeof expression',\n      # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'\n      # requires skipping the next token because we split on ' ' and '*'.\n      if tok.startswith('sizeof'):\n        skip_next = True\n        continue\n      is_const = False\n      break\n    if not is_const:\n      error(filename, linenum, 'runtime/arrays', 1,\n            'Do not use variable-length arrays.  Use an appropriately named '\n            \"('k' followed by CamelCase) compile-time constant for the size.\")\n\n  # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or\n  # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing\n  # in the class declaration.\n  match = Match(\n      (r'\\s*'\n       r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))'\n       r'\\(.*\\);$'),\n      line)\n  if match and linenum + 1 < clean_lines.NumLines():\n    next_line = clean_lines.elided[linenum + 1]\n    # We allow some, but not all, declarations of variables to be present\n    # in the statement that defines the class.  The [\\w\\*,\\s]* fragment of\n    # the regular expression below allows users to declare instances of\n    # the class or pointers to instances, but not less common types such\n    # as function pointers or arrays.  It's a tradeoff between allowing\n    # reasonable code and avoiding trying to parse more C++ using regexps.\n    if not Search(r'^\\s*}[\\w\\*,\\s]*;', next_line):\n      error(filename, linenum, 'readability/constructors', 3,\n            match.group(1) + ' should be the last thing in the class')\n\n  # Check for use of unnamed namespaces in header files.  Registration\n  # macros are typically OK, so we allow use of \"namespace {\" on lines\n  # that end with backslashes.\n  if (file_extension == 'h'\n      and Search(r'\\bnamespace\\s*{', line)\n      and line[-1] != '\\\\'):\n    error(filename, linenum, 'build/namespaces', 4,\n          'Do not use unnamed namespaces in header files.  See '\n          'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'\n          ' for more information.')\n\n\ndef CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,\n                    error):\n  \"\"\"Checks for a C-style cast by looking for the pattern.\n\n  This also handles sizeof(type) warnings, due to similarity of content.\n\n  Args:\n    filename: The name of the current file.\n    linenum: The number of the line to check.\n    line: The line of code to check.\n    raw_line: The raw line of code to check, with comments.\n    cast_type: The string for the C++ cast to recommend.  This is either\n      reinterpret_cast, static_cast, or const_cast, depending.\n    pattern: The regular expression used to find C-style casts.\n    error: The function to call with any errors found.\n\n  Returns:\n    True if an error was emitted.\n    False otherwise.\n  \"\"\"\n  match = Search(pattern, line)\n  if not match:\n    return False\n\n  # e.g., sizeof(int)\n  sizeof_match = Match(r'.*sizeof\\s*$', line[0:match.start(1) - 1])\n  if sizeof_match:\n    error(filename, linenum, 'runtime/sizeof', 1,\n          'Using sizeof(type).  Use sizeof(varname) instead if possible')\n    return True\n\n  remainder = line[match.end(0):]\n\n  # The close paren is for function pointers as arguments to a function.\n  # eg, void foo(void (*bar)(int));\n  # The semicolon check is a more basic function check; also possibly a\n  # function pointer typedef.\n  # eg, void foo(int); or void foo(int) const;\n  # The equals check is for function pointer assignment.\n  # eg, void *(*foo)(int) = ...\n  # The > is for MockCallback<...> ...\n  #\n  # Right now, this will only catch cases where there's a single argument, and\n  # it's unnamed.  It should probably be expanded to check for multiple\n  # arguments with some unnamed.\n  function_match = Match(r'\\s*(\\)|=|(const)?\\s*(;|\\{|throw\\(\\)|>))', remainder)\n  if function_match:\n    if (not function_match.group(3) or\n        function_match.group(3) == ';' or\n        ('MockCallback<' not in raw_line and\n         '/*' not in raw_line)):\n      error(filename, linenum, 'readability/function', 3,\n            'All parameters should be named in a function')\n    return True\n\n  # At this point, all that should be left is actual casts.\n  error(filename, linenum, 'readability/casting', 4,\n        'Using C-style cast.  Use %s<%s>(...) instead' %\n        (cast_type, match.group(1)))\n\n  return True\n\n\n_HEADERS_CONTAINING_TEMPLATES = (\n    ('<deque>', ('deque',)),\n    ('<functional>', ('unary_function', 'binary_function',\n                      'plus', 'minus', 'multiplies', 'divides', 'modulus',\n                      'negate',\n                      'equal_to', 'not_equal_to', 'greater', 'less',\n                      'greater_equal', 'less_equal',\n                      'logical_and', 'logical_or', 'logical_not',\n                      'unary_negate', 'not1', 'binary_negate', 'not2',\n                      'bind1st', 'bind2nd',\n                      'pointer_to_unary_function',\n                      'pointer_to_binary_function',\n                      'ptr_fun',\n                      'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',\n                      'mem_fun_ref_t',\n                      'const_mem_fun_t', 'const_mem_fun1_t',\n                      'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',\n                      'mem_fun_ref',\n                     )),\n    ('<limits>', ('numeric_limits',)),\n    ('<list>', ('list',)),\n    ('<map>', ('map', 'multimap',)),\n    ('<memory>', ('allocator',)),\n    ('<queue>', ('queue', 'priority_queue',)),\n    ('<set>', ('set', 'multiset',)),\n    ('<stack>', ('stack',)),\n    ('<string>', ('char_traits', 'basic_string',)),\n    ('<utility>', ('pair',)),\n    ('<vector>', ('vector',)),\n\n    # gcc extensions.\n    # Note: std::hash is their hash, ::hash is our hash\n    ('<hash_map>', ('hash_map', 'hash_multimap',)),\n    ('<hash_set>', ('hash_set', 'hash_multiset',)),\n    ('<slist>', ('slist',)),\n    )\n\n_RE_PATTERN_STRING = re.compile(r'\\bstring\\b')\n\n_re_pattern_algorithm_header = []\nfor _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',\n                  'transform'):\n  # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or\n  # type::max().\n  _re_pattern_algorithm_header.append(\n      (re.compile(r'[^>.]\\b' + _template + r'(<.*?>)?\\([^\\)]'),\n       _template,\n       '<algorithm>'))\n\n_re_pattern_templates = []\nfor _header, _templates in _HEADERS_CONTAINING_TEMPLATES:\n  for _template in _templates:\n    _re_pattern_templates.append(\n        (re.compile(r'(\\<|\\b)' + _template + r'\\s*\\<'),\n         _template + '<>',\n         _header))\n\n\ndef FilesBelongToSameModule(filename_cc, filename_h):\n  \"\"\"Check if these two filenames belong to the same module.\n\n  The concept of a 'module' here is a as follows:\n  foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the\n  same 'module' if they are in the same directory.\n  some/path/public/xyzzy and some/path/internal/xyzzy are also considered\n  to belong to the same module here.\n\n  If the filename_cc contains a longer path than the filename_h, for example,\n  '/absolute/path/to/base/sysinfo.cc', and this file would include\n  'base/sysinfo.h', this function also produces the prefix needed to open the\n  header. This is used by the caller of this function to more robustly open the\n  header file. We don't have access to the real include paths in this context,\n  so we need this guesswork here.\n\n  Known bugs: tools/base/bar.cc and base/bar.h belong to the same module\n  according to this implementation. Because of this, this function gives\n  some false positives. This should be sufficiently rare in practice.\n\n  Args:\n    filename_cc: is the path for the .cc file\n    filename_h: is the path for the header path\n\n  Returns:\n    Tuple with a bool and a string:\n    bool: True if filename_cc and filename_h belong to the same module.\n    string: the additional prefix needed to open the header file.\n  \"\"\"\n\n  if not filename_cc.endswith('.cc'):\n    return (False, '')\n  filename_cc = filename_cc[:-len('.cc')]\n  if filename_cc.endswith('_unittest'):\n    filename_cc = filename_cc[:-len('_unittest')]\n  elif filename_cc.endswith('_test'):\n    filename_cc = filename_cc[:-len('_test')]\n  filename_cc = filename_cc.replace('/public/', '/')\n  filename_cc = filename_cc.replace('/internal/', '/')\n\n  if not filename_h.endswith('.h'):\n    return (False, '')\n  filename_h = filename_h[:-len('.h')]\n  if filename_h.endswith('-inl'):\n    filename_h = filename_h[:-len('-inl')]\n  filename_h = filename_h.replace('/public/', '/')\n  filename_h = filename_h.replace('/internal/', '/')\n\n  files_belong_to_same_module = filename_cc.endswith(filename_h)\n  common_path = ''\n  if files_belong_to_same_module:\n    common_path = filename_cc[:-len(filename_h)]\n  return files_belong_to_same_module, common_path\n\n\ndef UpdateIncludeState(filename, include_state, io=codecs):\n  \"\"\"Fill up the include_state with new includes found from the file.\n\n  Args:\n    filename: the name of the header to read.\n    include_state: an _IncludeState instance in which the headers are inserted.\n    io: The io factory to use to read the file. Provided for testability.\n\n  Returns:\n    True if a header was succesfully added. False otherwise.\n  \"\"\"\n  headerfile = None\n  try:\n    headerfile = io.open(filename, 'r', 'utf8', 'replace')\n  except IOError:\n    return False\n  linenum = 0\n  for line in headerfile:\n    linenum += 1\n    clean_line = CleanseComments(line)\n    match = _RE_PATTERN_INCLUDE.search(clean_line)\n    if match:\n      include = match.group(2)\n      # The value formatting is cute, but not really used right now.\n      # What matters here is that the key is in include_state.\n      include_state.setdefault(include, '%s:%d' % (filename, linenum))\n  return True\n\n\ndef CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,\n                              io=codecs):\n  \"\"\"Reports for missing stl includes.\n\n  This function will output warnings to make sure you are including the headers\n  necessary for the stl containers and functions that you use. We only give one\n  reason to include a header. For example, if you use both equal_to<> and\n  less<> in a .h file, only one (the latter in the file) of these will be\n  reported as a reason to include the <functional>.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    include_state: An _IncludeState instance.\n    error: The function to call with any errors found.\n    io: The IO factory to use to read the header file. Provided for unittest\n        injection.\n  \"\"\"\n  required = {}  # A map of header name to linenumber and the template entity.\n                 # Example of required: { '<functional>': (1219, 'less<>') }\n\n  for linenum in range(clean_lines.NumLines()):\n    line = clean_lines.elided[linenum]\n    if not line or line[0] == '#':\n      continue\n\n    # String is special -- it is a non-templatized type in STL.\n    matched = _RE_PATTERN_STRING.search(line)\n    if matched:\n      # Don't warn about strings in non-STL namespaces:\n      # (We check only the first match per line; good enough.)\n      prefix = line[:matched.start()]\n      if prefix.endswith('std::') or not prefix.endswith('::'):\n        required['<string>'] = (linenum, 'string')\n\n    for pattern, template, header in _re_pattern_algorithm_header:\n      if pattern.search(line):\n        required[header] = (linenum, template)\n\n    # The following function is just a speed up, no semantics are changed.\n    if not '<' in line:  # Reduces the cpu time usage by skipping lines.\n      continue\n\n    for pattern, template, header in _re_pattern_templates:\n      if pattern.search(line):\n        required[header] = (linenum, template)\n\n  # The policy is that if you #include something in foo.h you don't need to\n  # include it again in foo.cc. Here, we will look at possible includes.\n  # Let's copy the include_state so it is only messed up within this function.\n  include_state = include_state.copy()\n\n  # Did we find the header for this file (if any) and succesfully load it?\n  header_found = False\n\n  # Use the absolute path so that matching works properly.\n  abs_filename = FileInfo(filename).FullName()\n\n  # For Emacs's flymake.\n  # If cpplint is invoked from Emacs's flymake, a temporary file is generated\n  # by flymake and that file name might end with '_flymake.cc'. In that case,\n  # restore original file name here so that the corresponding header file can be\n  # found.\n  # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'\n  # instead of 'foo_flymake.h'\n  abs_filename = re.sub(r'_flymake\\.cc$', '.cc', abs_filename)\n\n  # include_state is modified during iteration, so we iterate over a copy of\n  # the keys.\n  header_keys = list(include_state.keys())\n  for header in header_keys:\n    (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)\n    fullpath = common_path + header\n    if same_module and UpdateIncludeState(fullpath, include_state, io):\n      header_found = True\n\n  # If we can't find the header file for a .cc, assume it's because we don't\n  # know where to look. In that case we'll give up as we're not sure they\n  # didn't include it in the .h file.\n  # TODO(unknown): Do a better job of finding .h files so we are confident that\n  # not having the .h file means there isn't one.\n  if filename.endswith('.cc') and not header_found:\n    return\n\n  # All the lines have been processed, report the errors found.\n  for required_header_unstripped in required:\n    template = required[required_header_unstripped][1]\n    if required_header_unstripped.strip('<>\"') not in include_state:\n      error(filename, required[required_header_unstripped][0],\n            'build/include_what_you_use', 4,\n            'Add #include ' + required_header_unstripped + ' for ' + template)\n\n\n_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\\bmake_pair\\s*<')\n\n\ndef CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):\n  \"\"\"Check that make_pair's template arguments are deduced.\n\n  G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are\n  specified explicitly, and such use isn't intended in any case.\n\n  Args:\n    filename: The name of the current file.\n    clean_lines: A CleansedLines instance containing the file.\n    linenum: The number of the line to check.\n    error: The function to call with any errors found.\n  \"\"\"\n  raw = clean_lines.raw_lines\n  line = raw[linenum]\n  match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)\n  if match:\n    error(filename, linenum, 'build/explicit_make_pair',\n          4,  # 4 = high confidence\n          'Omit template arguments from make_pair OR use pair directly OR'\n          ' if appropriate, construct a pair directly')\n\n\ndef ProcessLine(filename, file_extension,\n                clean_lines, line, include_state, function_state,\n                class_state, error, extra_check_functions=[]):\n  \"\"\"Processes a single line in the file.\n\n  Args:\n    filename: Filename of the file that is being processed.\n    file_extension: The extension (dot not included) of the file.\n    clean_lines: An array of strings, each representing a line of the file,\n                 with comments stripped.\n    line: Number of line being processed.\n    include_state: An _IncludeState instance in which the headers are inserted.\n    function_state: A _FunctionState instance which counts function lines, etc.\n    class_state: A _ClassState instance which maintains information about\n                 the current stack of nested class declarations being parsed.\n    error: A callable to which errors are reported, which takes 4 arguments:\n           filename, line number, error level, and message\n    extra_check_functions: An array of additional check functions that will be\n                           run on each source line. Each function takes 4\n                           arguments: filename, clean_lines, line, error\n  \"\"\"\n  raw_lines = clean_lines.raw_lines\n  ParseNolintSuppressions(filename, raw_lines[line], line, error)\n  CheckForFunctionLengths(filename, clean_lines, line, function_state, error)\n  CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)\n  CheckStyle(filename, clean_lines, line, file_extension, class_state, error)\n  CheckLanguage(filename, clean_lines, line, file_extension, include_state,\n                error)\n  CheckForNonStandardConstructs(filename, clean_lines, line,\n                                class_state, error)\n  CheckPosixThreading(filename, clean_lines, line, error)\n  CheckInvalidIncrement(filename, clean_lines, line, error)\n  CheckMakePairUsesDeduction(filename, clean_lines, line, error)\n  for check_fn in extra_check_functions:\n    check_fn(filename, clean_lines, line, error)\n\ndef ProcessFileData(filename, file_extension, lines, error,\n                    extra_check_functions=[]):\n  \"\"\"Performs lint checks and reports any errors to the given error function.\n\n  Args:\n    filename: Filename of the file that is being processed.\n    file_extension: The extension (dot not included) of the file.\n    lines: An array of strings, each representing a line of the file, with the\n           last element being empty if the file is terminated with a newline.\n    error: A callable to which errors are reported, which takes 4 arguments:\n           filename, line number, error level, and message\n    extra_check_functions: An array of additional check functions that will be\n                           run on each source line. Each function takes 4\n                           arguments: filename, clean_lines, line, error\n  \"\"\"\n  lines = (['// marker so line numbers and indices both start at 1'] + lines +\n           ['// marker so line numbers end in a known way'])\n\n  include_state = _IncludeState()\n  function_state = _FunctionState()\n  class_state = _ClassState()\n\n  ResetNolintSuppressions()\n\n  CheckForCopyright(filename, lines, error)\n\n  if file_extension == 'h':\n    CheckForHeaderGuard(filename, lines, error)\n\n  RemoveMultiLineComments(filename, lines, error)\n  clean_lines = CleansedLines(lines)\n  for line in range(clean_lines.NumLines()):\n    ProcessLine(filename, file_extension, clean_lines, line,\n                include_state, function_state, class_state, error,\n                extra_check_functions)\n  class_state.CheckFinished(filename, error)\n\n  CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)\n\n  # We check here rather than inside ProcessLine so that we see raw\n  # lines rather than \"cleaned\" lines.\n  CheckForUnicodeReplacementCharacters(filename, lines, error)\n\n  CheckForNewlineAtEOF(filename, lines, error)\n\ndef ProcessFile(filename, vlevel, extra_check_functions=[]):\n  \"\"\"Does google-lint on a single file.\n\n  Args:\n    filename: The name of the file to parse.\n\n    vlevel: The level of errors to report.  Every error of confidence\n    >= verbose_level will be reported.  0 is a good default.\n\n    extra_check_functions: An array of additional check functions that will be\n                           run on each source line. Each function takes 4\n                           arguments: filename, clean_lines, line, error\n  \"\"\"\n\n  _SetVerboseLevel(vlevel)\n\n  try:\n    # Support the UNIX convention of using \"-\" for stdin.  Note that\n    # we are not opening the file with universal newline support\n    # (which codecs doesn't support anyway), so the resulting lines do\n    # contain trailing '\\r' characters if we are reading a file that\n    # has CRLF endings.\n    # If after the split a trailing '\\r' is present, it is removed\n    # below. If it is not expected to be present (i.e. os.linesep !=\n    # '\\r\\n' as in Windows), a warning is issued below if this file\n    # is processed.\n\n    if filename == '-':\n      lines = codecs.StreamReaderWriter(sys.stdin,\n                                        codecs.getreader('utf8'),\n                                        codecs.getwriter('utf8'),\n                                        'replace').read().split('\\n')\n    else:\n      lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\\n')\n\n    carriage_return_found = False\n    # Remove trailing '\\r'.\n    for linenum in range(len(lines)):\n      if lines[linenum].endswith('\\r'):\n        lines[linenum] = lines[linenum].rstrip('\\r')\n        carriage_return_found = True\n\n  except IOError:\n    sys.stderr.write(\n        \"Skipping input '%s': Can't open for reading\\n\" % filename)\n    return\n\n  # Note, if no dot is found, this will give the entire filename as the ext.\n  file_extension = filename[filename.rfind('.') + 1:]\n\n  # When reading from stdin, the extension is unknown, so no cpplint tests\n  # should rely on the extension.\n  if (filename != '-' and file_extension not in EXTENSIONS):\n    pass\n    # sys.stderr.write('Ignoring %s; extension not in %s\\n' % (filename, EXTENSIONS))\n  else:\n    ProcessFileData(filename, file_extension, lines, Error,\n                    extra_check_functions)\n    if carriage_return_found and os.linesep != '\\r\\n':\n      # Use 0 for linenum since outputting only one error for potentially\n      # several lines.\n      Error(filename, 0, 'whitespace/newline', 1,\n            'One or more unexpected \\\\r (^M) found;'\n            'better to use only a \\\\n')\n\n    sys.stderr.write('Done processing %s\\n' % filename)\n\n\ndef PrintUsage(message):\n  \"\"\"Prints a brief usage string and exits, optionally with an error message.\n\n  Args:\n    message: The optional error message.\n  \"\"\"\n  sys.stderr.write(_USAGE)\n\n  if message:\n    sys.exit('\\nFATAL ERROR: ' + message)\n  else:\n    sys.exit(1)\n\n\ndef PrintCategories():\n  \"\"\"Prints a list of all the error-categories used by error messages.\n\n  These are the categories used to filter messages via --filter.\n  \"\"\"\n  sys.stderr.write(''.join('  %s\\n' % cat for cat in _ERROR_CATEGORIES))\n  sys.exit(0)\n\n\ndef ParseArguments(args):\n  \"\"\"Parses the command line arguments.\n\n  This may set the output format and verbosity level as side-effects.\n\n  Args:\n    args: The command line arguments:\n\n  Returns:\n    The list of filenames to lint.\n  \"\"\"\n  try:\n    (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',\n                                                 'counting=',\n                                                 'filter='])\n  except getopt.GetoptError:\n    PrintUsage('Invalid arguments.')\n\n  verbosity = _VerboseLevel()\n  output_format = _OutputFormat()\n  filters = ''\n  counting_style = ''\n\n  for (opt, val) in opts:\n    if opt == '--help':\n      PrintUsage(None)\n    elif opt == '--output':\n      if not val in ('emacs', 'vs7'):\n        PrintUsage('The only allowed output formats are emacs and vs7.')\n      output_format = val\n    elif opt == '--verbose':\n      verbosity = int(val)\n    elif opt == '--filter':\n      filters = val\n      if not filters:\n        PrintCategories()\n    elif opt == '--counting':\n      if val not in ('total', 'toplevel', 'detailed'):\n        PrintUsage('Valid counting options are total, toplevel, and detailed')\n      counting_style = val\n\n  if not filenames:\n    PrintUsage('No files were specified.')\n\n  _SetOutputFormat(output_format)\n  _SetVerboseLevel(verbosity)\n  _SetFilters(filters)\n  _SetCountingStyle(counting_style)\n\n  return filenames\n\n\ndef main():\n  filenames = ParseArguments(sys.argv[1:])\n  backup_err = sys.stderr\n  try:\n    # Change stderr to write with replacement characters so we don't die\n    # if we try to print something containing non-ASCII characters.\n    sys.stderr = codecs.StreamReader(sys.stderr,\n                                     'replace')\n    _cpplint_state.ResetErrorCounts()\n    for filename in filenames:\n      ProcessFile(filename, _cpplint_state.verbose_level)\n    _cpplint_state.PrintErrorCounts()\n  finally:\n    sys.stderr = backup_err\n\n  sys.exit(_cpplint_state.error_count > 0)\n\n\nif __name__ == '__main__':\n  main()\n"
  },
  {
    "path": "utils/git-hooks/pep8.py",
    "content": "#!/usr/bin/env python\n# pep8.py - Check Python source code formatting, according to PEP 8\n# Copyright (C) 2006-2009 Johann C. Rocholl <johann@rocholl.net>\n# Copyright (C) 2009-2013 Florent Xicluna <florent.xicluna@gmail.com>\n#\n# Permission is hereby granted, free of charge, to any person\n# obtaining a copy of this software and associated documentation files\n# (the \"Software\"), to deal in the Software without restriction,\n# including without limitation the rights to use, copy, modify, merge,\n# publish, distribute, sublicense, and/or sell copies of the Software,\n# and to permit persons to whom the Software is furnished to do so,\n# subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS 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\n# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n# 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\n# SOFTWARE.\n\nr\"\"\"\nCheck Python source code formatting, according to PEP 8:\nhttp://www.python.org/dev/peps/pep-0008/\n\nFor usage and a list of options, try this:\n$ python pep8.py -h\n\nThis program and its regression test suite live here:\nhttp://github.com/jcrocholl/pep8\n\nGroups of errors and warnings:\nE errors\nW warnings\n100 indentation\n200 whitespace\n300 blank lines\n400 imports\n500 line length\n600 deprecation\n700 statements\n900 syntax error\n\"\"\"\n__version__ = '1.4.6'\n\nimport os\nimport sys\nimport re\nimport time\nimport inspect\nimport keyword\nimport tokenize\nfrom optparse import OptionParser\nfrom fnmatch import fnmatch\ntry:\n    from configparser import RawConfigParser\n    from io import TextIOWrapper\nexcept ImportError:\n    from ConfigParser import RawConfigParser\n\nDEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__'\nDEFAULT_IGNORE = 'E123,E226,E24'\nif sys.platform == 'win32':\n    DEFAULT_CONFIG = os.path.expanduser(r'~\\.pep8')\nelse:\n    DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or\n                                  os.path.expanduser('~/.config'), 'pep8')\nPROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8')\nTESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')\nMAX_LINE_LENGTH = 79\nREPORT_FORMAT = {\n    'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',\n    'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',\n}\n\nPyCF_ONLY_AST = 1024\nSINGLETONS = frozenset(['False', 'None', 'True'])\nKEYWORDS = frozenset(keyword.kwlist + ['print']) - SINGLETONS\nUNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])\nARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-'])\nWS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])\nWS_NEEDED_OPERATORS = frozenset([\n    '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',\n    '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '='])\nWHITESPACE = frozenset(' \\t')\nSKIP_TOKENS = frozenset([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE,\n                         tokenize.INDENT, tokenize.DEDENT])\nBENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']\n\nINDENT_REGEX = re.compile(r'([ \\t]*)')\nRAISE_COMMA_REGEX = re.compile(r'raise\\s+\\w+\\s*,')\nRERAISE_COMMA_REGEX = re.compile(r'raise\\s+\\w+\\s*,\\s*\\w+\\s*,\\s*\\w+')\nERRORCODE_REGEX = re.compile(r'\\b[A-Z]\\d{3}\\b')\nDOCSTRING_REGEX = re.compile(r'u?r?[\"\\']')\nEXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')\nWHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\\s*(?:  |\\t)')\nCOMPARE_SINGLETON_REGEX = re.compile(r'([=!]=)\\s*(None|False|True)')\nCOMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\\s+not)?)\\s*type(?:s.\\w+Type'\n                                r'|\\s*\\(\\s*([^)]*[^ )])\\s*\\))')\nKEYWORD_REGEX = re.compile(r'(\\s*)\\b(?:%s)\\b(\\s*)' % r'|'.join(KEYWORDS))\nOPERATOR_REGEX = re.compile(r'(?:[^,\\s])(\\s*)(?:[-+*/|!<=>%&^]+)(\\s*)')\nLAMBDA_REGEX = re.compile(r'\\blambda\\b')\nHUNK_REGEX = re.compile(r'^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,(\\d+))? @@.*$')\n\n# Work around Python < 2.6 behaviour, which does not generate NL after\n# a comment which is on a line by itself.\nCOMMENT_WITH_NL = tokenize.generate_tokens(['#\\n'].pop).send(None)[1] == '#\\n'\n\n\n##############################################################################\n# Plugins (check functions) for physical lines\n##############################################################################\n\n\ndef tabs_or_spaces(physical_line, indent_char):\n    r\"\"\"\n    Never mix tabs and spaces.\n\n    The most popular way of indenting Python is with spaces only.  The\n    second-most popular way is with tabs only.  Code indented with a mixture\n    of tabs and spaces should be converted to using spaces exclusively.  When\n    invoking the Python command line interpreter with the -t option, it issues\n    warnings about code that illegally mixes tabs and spaces.  When using -tt\n    these warnings become errors.  These options are highly recommended!\n\n    Okay: if a == 0:\\n        a = 1\\n        b = 1\n    E101: if a == 0:\\n        a = 1\\n\\tb = 1\n    \"\"\"\n    indent = INDENT_REGEX.match(physical_line).group(1)\n    for offset, char in enumerate(indent):\n        if char != indent_char:\n            return offset, \"E101 indentation contains mixed spaces and tabs\"\n\n\ndef tabs_obsolete(physical_line):\n    r\"\"\"\n    For new projects, spaces-only are strongly recommended over tabs.  Most\n    editors have features that make this easy to do.\n\n    Okay: if True:\\n    return\n    W191: if True:\\n\\treturn\n    \"\"\"\n    indent = INDENT_REGEX.match(physical_line).group(1)\n    if '\\t' in indent:\n        return indent.index('\\t'), \"W191 indentation contains tabs\"\n\n\ndef trailing_whitespace(physical_line):\n    r\"\"\"\n    JCR: Trailing whitespace is superfluous.\n    FBM: Except when it occurs as part of a blank line (i.e. the line is\n         nothing but whitespace). According to Python docs[1] a line with only\n         whitespace is considered a blank line, and is to be ignored. However,\n         matching a blank line to its indentation level avoids mistakenly\n         terminating a multi-line statement (e.g. class declaration) when\n         pasting code into the standard Python interpreter.\n\n         [1] http://docs.python.org/reference/lexical_analysis.html#blank-lines\n\n    The warning returned varies on whether the line itself is blank, for easier\n    filtering for those who want to indent their blank lines.\n\n    Okay: spam(1)\\n#\n    W291: spam(1) \\n#\n    W293: class Foo(object):\\n    \\n    bang = 12\n    \"\"\"\n    physical_line = physical_line.rstrip('\\n')    # chr(10), newline\n    physical_line = physical_line.rstrip('\\r')    # chr(13), carriage return\n    physical_line = physical_line.rstrip('\\x0c')  # chr(12), form feed, ^L\n    stripped = physical_line.rstrip(' \\t\\v')\n    if physical_line != stripped:\n        if stripped:\n            return len(stripped), \"W291 trailing whitespace\"\n        else:\n            return 0, \"W293 blank line contains whitespace\"\n\n\ndef trailing_blank_lines(physical_line, lines, line_number):\n    r\"\"\"\n    JCR: Trailing blank lines are superfluous.\n\n    Okay: spam(1)\n    W391: spam(1)\\n\n    \"\"\"\n    if not physical_line.rstrip() and line_number == len(lines):\n        return 0, \"W391 blank line at end of file\"\n\n\ndef missing_newline(physical_line):\n    \"\"\"\n    JCR: The last line should have a newline.\n\n    Reports warning W292.\n    \"\"\"\n    if physical_line.rstrip() == physical_line:\n        return len(physical_line), \"W292 no newline at end of file\"\n\n\ndef maximum_line_length(physical_line, max_line_length):\n    \"\"\"\n    Limit all lines to a maximum of 79 characters.\n\n    There are still many devices around that are limited to 80 character\n    lines; plus, limiting windows to 80 characters makes it possible to have\n    several windows side-by-side.  The default wrapping on such devices looks\n    ugly.  Therefore, please limit all lines to a maximum of 79 characters.\n    For flowing long blocks of text (docstrings or comments), limiting the\n    length to 72 characters is recommended.\n\n    Reports error E501.\n    \"\"\"\n    line = physical_line.rstrip()\n    length = len(line)\n    if length > max_line_length and not noqa(line):\n        if hasattr(line, 'decode'):   # Python 2\n            # The line could contain multi-byte characters\n            try:\n                length = len(line.decode('utf-8'))\n            except UnicodeError:\n                pass\n        if length > max_line_length:\n            return (max_line_length, \"E501 line too long \"\n                    \"(%d > %d characters)\" % (length, max_line_length))\n\n\n##############################################################################\n# Plugins (check functions) for logical lines\n##############################################################################\n\n\ndef blank_lines(logical_line, blank_lines, indent_level, line_number,\n                previous_logical, previous_indent_level):\n    r\"\"\"\n    Separate top-level function and class definitions with two blank lines.\n\n    Method definitions inside a class are separated by a single blank line.\n\n    Extra blank lines may be used (sparingly) to separate groups of related\n    functions.  Blank lines may be omitted between a bunch of related\n    one-liners (e.g. a set of dummy implementations).\n\n    Use blank lines in functions, sparingly, to indicate logical sections.\n\n    Okay: def a():\\n    pass\\n\\n\\ndef b():\\n    pass\n    Okay: def a():\\n    pass\\n\\n\\n# Foo\\n# Bar\\n\\ndef b():\\n    pass\n\n    E301: class Foo:\\n    b = 0\\n    def bar():\\n        pass\n    E302: def a():\\n    pass\\n\\ndef b(n):\\n    pass\n    E303: def a():\\n    pass\\n\\n\\n\\ndef b(n):\\n    pass\n    E303: def a():\\n\\n\\n\\n    pass\n    E304: @decorator\\n\\ndef a():\\n    pass\n    \"\"\"\n    if line_number < 3 and not previous_logical:\n        return  # Don't expect blank lines before the first line\n    if previous_logical.startswith('@'):\n        if blank_lines:\n            yield 0, \"E304 blank lines found after function decorator\"\n    elif blank_lines > 2 or (indent_level and blank_lines == 2):\n        yield 0, \"E303 too many blank lines (%d)\" % blank_lines\n    elif logical_line.startswith(('def ', 'class ', '@')):\n        if indent_level:\n            if not (blank_lines or previous_indent_level < indent_level or\n                    DOCSTRING_REGEX.match(previous_logical)):\n                yield 0, \"E301 expected 1 blank line, found 0\"\n        elif blank_lines != 2:\n            yield 0, \"E302 expected 2 blank lines, found %d\" % blank_lines\n\n\ndef extraneous_whitespace(logical_line):\n    \"\"\"\n    Avoid extraneous whitespace in the following situations:\n\n    - Immediately inside parentheses, brackets or braces.\n\n    - Immediately before a comma, semicolon, or colon.\n\n    Okay: spam(ham[1], {eggs: 2})\n    E201: spam( ham[1], {eggs: 2})\n    E201: spam(ham[ 1], {eggs: 2})\n    E201: spam(ham[1], { eggs: 2})\n    E202: spam(ham[1], {eggs: 2} )\n    E202: spam(ham[1 ], {eggs: 2})\n    E202: spam(ham[1], {eggs: 2 })\n\n    E203: if x == 4: print x, y; x, y = y , x\n    E203: if x == 4: print x, y ; x, y = y, x\n    E203: if x == 4 : print x, y; x, y = y, x\n    \"\"\"\n    line = logical_line\n    for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):\n        text = match.group()\n        char = text.strip()\n        found = match.start()\n        if text == char + ' ':\n            # assert char in '([{'\n            yield found + 1, \"E201 whitespace after '%s'\" % char\n        elif line[found - 1] != ',':\n            code = ('E202' if char in '}])' else 'E203')  # if char in ',;:'\n            yield found, \"%s whitespace before '%s'\" % (code, char)\n\n\ndef whitespace_around_keywords(logical_line):\n    r\"\"\"\n    Avoid extraneous whitespace around keywords.\n\n    Okay: True and False\n    E271: True and  False\n    E272: True  and False\n    E273: True and\\tFalse\n    E274: True\\tand False\n    \"\"\"\n    for match in KEYWORD_REGEX.finditer(logical_line):\n        before, after = match.groups()\n\n        if '\\t' in before:\n            yield match.start(1), \"E274 tab before keyword\"\n        elif len(before) > 1:\n            yield match.start(1), \"E272 multiple spaces before keyword\"\n\n        if '\\t' in after:\n            yield match.start(2), \"E273 tab after keyword\"\n        elif len(after) > 1:\n            yield match.start(2), \"E271 multiple spaces after keyword\"\n\n\ndef missing_whitespace(logical_line):\n    \"\"\"\n    JCR: Each comma, semicolon or colon should be followed by whitespace.\n\n    Okay: [a, b]\n    Okay: (3,)\n    Okay: a[1:4]\n    Okay: a[:4]\n    Okay: a[1:]\n    Okay: a[1:4:2]\n    E231: ['a','b']\n    E231: foo(bar,baz)\n    E231: [{'a':'b'}]\n    \"\"\"\n    line = logical_line\n    for index in range(len(line) - 1):\n        char = line[index]\n        if char in ',;:' and line[index + 1] not in WHITESPACE:\n            before = line[:index]\n            if char == ':' and before.count('[') > before.count(']') and \\\n                    before.rfind('{') < before.rfind('['):\n                continue  # Slice syntax, no space required\n            if char == ',' and line[index + 1] == ')':\n                continue  # Allow tuple with only one element: (3,)\n            yield index, \"E231 missing whitespace after '%s'\" % char\n\n\ndef indentation(logical_line, previous_logical, indent_char,\n                indent_level, previous_indent_level):\n    r\"\"\"\n    Use 4 spaces per indentation level.\n\n    For really old code that you don't want to mess up, you can continue to\n    use 8-space tabs.\n\n    Okay: a = 1\n    Okay: if a == 0:\\n    a = 1\n    E111:   a = 1\n\n    Okay: for item in items:\\n    pass\n    E112: for item in items:\\npass\n\n    Okay: a = 1\\nb = 2\n    E113: a = 1\\n    b = 2\n    \"\"\"\n    if indent_char == ' ' and indent_level % 4:\n        yield 0, \"E111 indentation is not a multiple of four\"\n    indent_expect = previous_logical.endswith(':')\n    if indent_expect and indent_level <= previous_indent_level:\n        yield 0, \"E112 expected an indented block\"\n    if indent_level > previous_indent_level and not indent_expect:\n        yield 0, \"E113 unexpected indentation\"\n\n\ndef continued_indentation(logical_line, tokens, indent_level, hang_closing,\n                          noqa, verbose):\n    r\"\"\"\n    Continuation lines should align wrapped elements either vertically using\n    Python's implicit line joining inside parentheses, brackets and braces, or\n    using a hanging indent.\n\n    When using a hanging indent the following considerations should be applied:\n\n    - there should be no arguments on the first line, and\n\n    - further indentation should be used to clearly distinguish itself as a\n      continuation line.\n\n    Okay: a = (\\n)\n    E123: a = (\\n    )\n\n    Okay: a = (\\n    42)\n    E121: a = (\\n   42)\n    E122: a = (\\n42)\n    E123: a = (\\n    42\\n    )\n    E124: a = (24,\\n     42\\n)\n    E125: if (a or\\n    b):\\n    pass\n    E126: a = (\\n        42)\n    E127: a = (24,\\n      42)\n    E128: a = (24,\\n    42)\n    \"\"\"\n    first_row = tokens[0][2][0]\n    nrows = 1 + tokens[-1][2][0] - first_row\n    if noqa or nrows == 1:\n        return\n\n    # indent_next tells us whether the next block is indented; assuming\n    # that it is indented by 4 spaces, then we should not allow 4-space\n    # indents on the final continuation line; in turn, some other\n    # indents are allowed to have an extra 4 spaces.\n    indent_next = logical_line.endswith(':')\n\n    row = depth = 0\n    # remember how many brackets were opened on each line\n    parens = [0] * nrows\n    # relative indents of physical lines\n    rel_indent = [0] * nrows\n    # visual indents\n    indent_chances = {}\n    last_indent = tokens[0][2]\n    indent = [last_indent[1]]\n    if verbose >= 3:\n        print(\">>> \" + tokens[0][4].rstrip())\n\n    for token_type, text, start, end, line in tokens:\n\n        newline = row < start[0] - first_row\n        if newline:\n            row = start[0] - first_row\n            newline = (not last_token_multiline and\n                       token_type not in (tokenize.NL, tokenize.NEWLINE))\n\n        if newline:\n            # this is the beginning of a continuation line.\n            last_indent = start\n            if verbose >= 3:\n                print(\"... \" + line.rstrip())\n\n            # record the initial indent.\n            rel_indent[row] = expand_indent(line) - indent_level\n\n            if depth:\n                # a bracket expression in a continuation line.\n                # find the line that it was opened on\n                for open_row in range(row - 1, -1, -1):\n                    if parens[open_row]:\n                        break\n            else:\n                # an unbracketed continuation line (ie, backslash)\n                open_row = 0\n            hang = rel_indent[row] - rel_indent[open_row]\n            close_bracket = (token_type == tokenize.OP and text in ']})')\n            visual_indent = (not close_bracket and hang > 0 and\n                             indent_chances.get(start[1]))\n\n            if close_bracket and indent[depth]:\n                # closing bracket for visual indent\n                if start[1] != indent[depth]:\n                    yield (start, \"E124 closing bracket does not match \"\n                           \"visual indentation\")\n            elif close_bracket and not hang:\n                # closing bracket matches indentation of opening bracket's line\n                if hang_closing:\n                    yield start, \"E133 closing bracket is missing indentation\"\n            elif visual_indent is True:\n                # visual indent is verified\n                if not indent[depth]:\n                    indent[depth] = start[1]\n            elif visual_indent in (text, str):\n                # ignore token lined up with matching one from a previous line\n                pass\n            elif indent[depth] and start[1] < indent[depth]:\n                # visual indent is broken\n                yield (start, \"E128 continuation line \"\n                       \"under-indented for visual indent\")\n            elif hang == 4 or (indent_next and rel_indent[row] == 8):\n                # hanging indent is verified\n                if close_bracket and not hang_closing:\n                    yield (start, \"E123 closing bracket does not match \"\n                           \"indentation of opening bracket's line\")\n            else:\n                # indent is broken\n                if hang <= 0:\n                    error = \"E122\", \"missing indentation or outdented\"\n                elif indent[depth]:\n                    error = \"E127\", \"over-indented for visual indent\"\n                elif hang % 4:\n                    error = \"E121\", \"indentation is not a multiple of four\"\n                else:\n                    error = \"E126\", \"over-indented for hanging indent\"\n                yield start, \"%s continuation line %s\" % error\n\n        # look for visual indenting\n        if (parens[row] and token_type not in (tokenize.NL, tokenize.COMMENT)\n                and not indent[depth]):\n            indent[depth] = start[1]\n            indent_chances[start[1]] = True\n            if verbose >= 4:\n                print(\"bracket depth %s indent to %s\" % (depth, start[1]))\n        # deal with implicit string concatenation\n        elif (token_type in (tokenize.STRING, tokenize.COMMENT) or\n              text in ('u', 'ur', 'b', 'br')):\n            indent_chances[start[1]] = str\n        # special case for the \"if\" statement because len(\"if (\") == 4\n        elif not indent_chances and not row and not depth and text == 'if':\n            indent_chances[end[1] + 1] = True\n\n        # keep track of bracket depth\n        if token_type == tokenize.OP:\n            if text in '([{':\n                depth += 1\n                indent.append(0)\n                parens[row] += 1\n                if verbose >= 4:\n                    print(\"bracket depth %s seen, col %s, visual min = %s\" %\n                          (depth, start[1], indent[depth]))\n            elif text in ')]}' and depth > 0:\n                # parent indents should not be more than this one\n                prev_indent = indent.pop() or last_indent[1]\n                for d in range(depth):\n                    if indent[d] > prev_indent:\n                        indent[d] = 0\n                for ind in list(indent_chances):\n                    if ind >= prev_indent:\n                        del indent_chances[ind]\n                depth -= 1\n                if depth:\n                    indent_chances[indent[depth]] = True\n                for idx in range(row, -1, -1):\n                    if parens[idx]:\n                        parens[idx] -= 1\n                        rel_indent[row] = rel_indent[idx]\n                        break\n            assert len(indent) == depth + 1\n            if start[1] not in indent_chances:\n                # allow to line up tokens\n                indent_chances[start[1]] = text\n\n        last_token_multiline = (start[0] != end[0])\n\n    if indent_next and expand_indent(line) == indent_level + 4:\n        yield (last_indent, \"E125 continuation line does not distinguish \"\n               \"itself from next logical line\")\n\n\ndef whitespace_before_parameters(logical_line, tokens):\n    \"\"\"\n    Avoid extraneous whitespace in the following situations:\n\n    - Immediately before the open parenthesis that starts the argument\n      list of a function call.\n\n    - Immediately before the open parenthesis that starts an indexing or\n      slicing.\n\n    Okay: spam(1)\n    E211: spam (1)\n\n    Okay: dict['key'] = list[index]\n    E211: dict ['key'] = list[index]\n    E211: dict['key'] = list [index]\n    \"\"\"\n    prev_type, prev_text, __, prev_end, __ = tokens[0]\n    for index in range(1, len(tokens)):\n        token_type, text, start, end, __ = tokens[index]\n        if (token_type == tokenize.OP and\n            text in '([' and\n            start != prev_end and\n            (prev_type == tokenize.NAME or prev_text in '}])') and\n            # Syntax \"class A (B):\" is allowed, but avoid it\n            (index < 2 or tokens[index - 2][1] != 'class') and\n                # Allow \"return (a.foo for a in range(5))\"\n                not keyword.iskeyword(prev_text)):\n            yield prev_end, \"E211 whitespace before '%s'\" % text\n        prev_type = token_type\n        prev_text = text\n        prev_end = end\n\n\ndef whitespace_around_operator(logical_line):\n    r\"\"\"\n    Avoid extraneous whitespace in the following situations:\n\n    - More than one space around an assignment (or other) operator to\n      align it with another.\n\n    Okay: a = 12 + 3\n    E221: a = 4  + 5\n    E222: a = 4 +  5\n    E223: a = 4\\t+ 5\n    E224: a = 4 +\\t5\n    \"\"\"\n    for match in OPERATOR_REGEX.finditer(logical_line):\n        before, after = match.groups()\n\n        if '\\t' in before:\n            yield match.start(1), \"E223 tab before operator\"\n        elif len(before) > 1:\n            yield match.start(1), \"E221 multiple spaces before operator\"\n\n        if '\\t' in after:\n            yield match.start(2), \"E224 tab after operator\"\n        elif len(after) > 1:\n            yield match.start(2), \"E222 multiple spaces after operator\"\n\n\ndef missing_whitespace_around_operator(logical_line, tokens):\n    r\"\"\"\n    - Always surround these binary operators with a single space on\n      either side: assignment (=), augmented assignment (+=, -= etc.),\n      comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not),\n      Booleans (and, or, not).\n\n    - Use spaces around arithmetic operators.\n\n    Okay: i = i + 1\n    Okay: submitted += 1\n    Okay: x = x * 2 - 1\n    Okay: hypot2 = x * x + y * y\n    Okay: c = (a + b) * (a - b)\n    Okay: foo(bar, key='word', *args, **kwargs)\n    Okay: alpha[:-i]\n\n    E225: i=i+1\n    E225: submitted +=1\n    E225: x = x /2 - 1\n    E225: z = x **y\n    E226: c = (a+b) * (a-b)\n    E226: hypot2 = x*x + y*y\n    E227: c = a|b\n    E228: msg = fmt%(errno, errmsg)\n    \"\"\"\n    parens = 0\n    need_space = False\n    prev_type = tokenize.OP\n    prev_text = prev_end = None\n    for token_type, text, start, end, line in tokens:\n        if token_type in (tokenize.NL, tokenize.NEWLINE, tokenize.ERRORTOKEN):\n            # ERRORTOKEN is triggered by backticks in Python 3\n            continue\n        if text in ('(', 'lambda'):\n            parens += 1\n        elif text == ')':\n            parens -= 1\n        if need_space:\n            if start != prev_end:\n                # Found a (probably) needed space\n                if need_space is not True and not need_space[1]:\n                    yield (need_space[0],\n                           \"E225 missing whitespace around operator\")\n                need_space = False\n            elif text == '>' and prev_text in ('<', '-'):\n                # Tolerate the \"<>\" operator, even if running Python 3\n                # Deal with Python 3's annotated return value \"->\"\n                pass\n            else:\n                if need_space is True or need_space[1]:\n                    # A needed trailing space was not found\n                    yield prev_end, \"E225 missing whitespace around operator\"\n                else:\n                    code, optype = 'E226', 'arithmetic'\n                    if prev_text == '%':\n                        code, optype = 'E228', 'modulo'\n                    elif prev_text not in ARITHMETIC_OP:\n                        code, optype = 'E227', 'bitwise or shift'\n                    yield (need_space[0], \"%s missing whitespace \"\n                           \"around %s operator\" % (code, optype))\n                need_space = False\n        elif token_type == tokenize.OP and prev_end is not None:\n            if text == '=' and parens:\n                # Allow keyword args or defaults: foo(bar=None).\n                pass\n            elif text in WS_NEEDED_OPERATORS:\n                need_space = True\n            elif text in UNARY_OPERATORS:\n                # Check if the operator is being used as a binary operator\n                # Allow unary operators: -123, -x, +1.\n                # Allow argument unpacking: foo(*args, **kwargs).\n                if prev_type == tokenize.OP:\n                    binary_usage = (prev_text in '}])')\n                elif prev_type == tokenize.NAME:\n                    binary_usage = (prev_text not in KEYWORDS)\n                else:\n                    binary_usage = (prev_type not in SKIP_TOKENS)\n\n                if binary_usage:\n                    need_space = None\n            elif text in WS_OPTIONAL_OPERATORS:\n                need_space = None\n\n            if need_space is None:\n                # Surrounding space is optional, but ensure that\n                # trailing space matches opening space\n                need_space = (prev_end, start != prev_end)\n            elif need_space and start == prev_end:\n                # A needed opening space was not found\n                yield prev_end, \"E225 missing whitespace around operator\"\n                need_space = False\n        prev_type = token_type\n        prev_text = text\n        prev_end = end\n\n\ndef whitespace_around_comma(logical_line):\n    r\"\"\"\n    Avoid extraneous whitespace in the following situations:\n\n    - More than one space around an assignment (or other) operator to\n      align it with another.\n\n    Note: these checks are disabled by default\n\n    Okay: a = (1, 2)\n    E241: a = (1,  2)\n    E242: a = (1,\\t2)\n    \"\"\"\n    line = logical_line\n    for m in WHITESPACE_AFTER_COMMA_REGEX.finditer(line):\n        found = m.start() + 1\n        if '\\t' in m.group():\n            yield found, \"E242 tab after '%s'\" % m.group()[0]\n        else:\n            yield found, \"E241 multiple spaces after '%s'\" % m.group()[0]\n\n\ndef whitespace_around_named_parameter_equals(logical_line, tokens):\n    \"\"\"\n    Don't use spaces around the '=' sign when used to indicate a\n    keyword argument or a default parameter value.\n\n    Okay: def complex(real, imag=0.0):\n    Okay: return magic(r=real, i=imag)\n    Okay: boolean(a == b)\n    Okay: boolean(a != b)\n    Okay: boolean(a <= b)\n    Okay: boolean(a >= b)\n\n    E251: def complex(real, imag = 0.0):\n    E251: return magic(r = real, i = imag)\n    \"\"\"\n    parens = 0\n    no_space = False\n    prev_end = None\n    message = \"E251 unexpected spaces around keyword / parameter equals\"\n    for token_type, text, start, end, line in tokens:\n        if no_space:\n            no_space = False\n            if start != prev_end:\n                yield (prev_end, message)\n        elif token_type == tokenize.OP:\n            if text == '(':\n                parens += 1\n            elif text == ')':\n                parens -= 1\n            elif parens and text == '=':\n                no_space = True\n                if start != prev_end:\n                    yield (prev_end, message)\n        prev_end = end\n\n\ndef whitespace_before_inline_comment(logical_line, tokens):\n    \"\"\"\n    Separate inline comments by at least two spaces.\n\n    An inline comment is a comment on the same line as a statement.  Inline\n    comments should be separated by at least two spaces from the statement.\n    They should start with a # and a single space.\n\n    Okay: x = x + 1  # Increment x\n    Okay: x = x + 1    # Increment x\n    E261: x = x + 1 # Increment x\n    E262: x = x + 1  #Increment x\n    E262: x = x + 1  #  Increment x\n    \"\"\"\n    prev_end = (0, 0)\n    for token_type, text, start, end, line in tokens:\n        if token_type == tokenize.COMMENT:\n            if not line[:start[1]].strip():\n                continue\n            if prev_end[0] == start[0] and start[1] < prev_end[1] + 2:\n                yield (prev_end,\n                       \"E261 at least two spaces before inline comment\")\n            symbol, sp, comment = text.partition(' ')\n            if symbol not in ('#', '#:') or comment[:1].isspace():\n                yield start, \"E262 inline comment should start with '# '\"\n        elif token_type != tokenize.NL:\n            prev_end = end\n\n\ndef imports_on_separate_lines(logical_line):\n    r\"\"\"\n    Imports should usually be on separate lines.\n\n    Okay: import os\\nimport sys\n    E401: import sys, os\n\n    Okay: from subprocess import Popen, PIPE\n    Okay: from myclas import MyClass\n    Okay: from foo.bar.yourclass import YourClass\n    Okay: import myclass\n    Okay: import foo.bar.yourclass\n    \"\"\"\n    line = logical_line\n    if line.startswith('import '):\n        found = line.find(',')\n        if -1 < found and ';' not in line[:found]:\n            yield found, \"E401 multiple imports on one line\"\n\n\ndef compound_statements(logical_line):\n    r\"\"\"\n    Compound statements (multiple statements on the same line) are\n    generally discouraged.\n\n    While sometimes it's okay to put an if/for/while with a small body\n    on the same line, never do this for multi-clause statements. Also\n    avoid folding such long lines!\n\n    Okay: if foo == 'blah':\\n    do_blah_thing()\n    Okay: do_one()\n    Okay: do_two()\n    Okay: do_three()\n\n    E701: if foo == 'blah': do_blah_thing()\n    E701: for x in lst: total += x\n    E701: while t < 10: t = delay()\n    E701: if foo == 'blah': do_blah_thing()\n    E701: else: do_non_blah_thing()\n    E701: try: something()\n    E701: finally: cleanup()\n    E701: if foo == 'blah': one(); two(); three()\n\n    E702: do_one(); do_two(); do_three()\n    E703: do_four();  # useless semicolon\n    \"\"\"\n    line = logical_line\n    last_char = len(line) - 1\n    found = line.find(':')\n    while -1 < found < last_char:\n        before = line[:found]\n        if (before.count('{') <= before.count('}') and  # {'a': 1} (dict)\n            before.count('[') <= before.count(']') and  # [1:2] (slice)\n            before.count('(') <= before.count(')') and  # (Python 3 annotation)\n                not LAMBDA_REGEX.search(before)):       # lambda x: x\n            yield found, \"E701 multiple statements on one line (colon)\"\n        found = line.find(':', found + 1)\n    found = line.find(';')\n    while -1 < found:\n        if found < last_char:\n            yield found, \"E702 multiple statements on one line (semicolon)\"\n        else:\n            yield found, \"E703 statement ends with a semicolon\"\n        found = line.find(';', found + 1)\n\n\ndef explicit_line_join(logical_line, tokens):\n    r\"\"\"\n    Avoid explicit line join between brackets.\n\n    The preferred way of wrapping long lines is by using Python's implied line\n    continuation inside parentheses, brackets and braces.  Long lines can be\n    broken over multiple lines by wrapping expressions in parentheses.  These\n    should be used in preference to using a backslash for line continuation.\n\n    E502: aaa = [123, \\\\n       123]\n    E502: aaa = (\"bbb \" \\\\n       \"ccc\")\n\n    Okay: aaa = [123,\\n       123]\n    Okay: aaa = (\"bbb \"\\n       \"ccc\")\n    Okay: aaa = \"bbb \" \\\\n    \"ccc\"\n    \"\"\"\n    prev_start = prev_end = parens = 0\n    for token_type, text, start, end, line in tokens:\n        if start[0] != prev_start and parens and backslash:\n            yield backslash, \"E502 the backslash is redundant between brackets\"\n        if end[0] != prev_end:\n            if line.rstrip('\\r\\n').endswith('\\\\'):\n                backslash = (end[0], len(line.splitlines()[-1]) - 1)\n            else:\n                backslash = None\n            prev_start = prev_end = end[0]\n        else:\n            prev_start = start[0]\n        if token_type == tokenize.OP:\n            if text in '([{':\n                parens += 1\n            elif text in ')]}':\n                parens -= 1\n\n\ndef comparison_to_singleton(logical_line, noqa):\n    \"\"\"\n    Comparisons to singletons like None should always be done\n    with \"is\" or \"is not\", never the equality operators.\n\n    Okay: if arg is not None:\n    E711: if arg != None:\n    E712: if arg == True:\n\n    Also, beware of writing if x when you really mean if x is not None --\n    e.g. when testing whether a variable or argument that defaults to None was\n    set to some other value.  The other value might have a type (such as a\n    container) that could be false in a boolean context!\n    \"\"\"\n    match = not noqa and COMPARE_SINGLETON_REGEX.search(logical_line)\n    if match:\n        same = (match.group(1) == '==')\n        singleton = match.group(2)\n        msg = \"'if cond is %s:'\" % (('' if same else 'not ') + singleton)\n        if singleton in ('None',):\n            code = 'E711'\n        else:\n            code = 'E712'\n            nonzero = ((singleton == 'True' and same) or\n                       (singleton == 'False' and not same))\n            msg += \" or 'if %scond:'\" % ('' if nonzero else 'not ')\n        yield match.start(1), (\"%s comparison to %s should be %s\" %\n                               (code, singleton, msg))\n\n\ndef comparison_type(logical_line):\n    \"\"\"\n    Object type comparisons should always use isinstance() instead of\n    comparing types directly.\n\n    Okay: if isinstance(obj, int):\n    E721: if type(obj) is type(1):\n\n    When checking if an object is a string, keep in mind that it might be a\n    unicode string too! In Python 2.3, str and unicode have a common base\n    class, basestring, so you can do:\n\n    Okay: if isinstance(obj, basestring):\n    Okay: if type(a1) is type(b1):\n    \"\"\"\n    match = COMPARE_TYPE_REGEX.search(logical_line)\n    if match:\n        inst = match.group(1)\n        if inst and isidentifier(inst) and inst not in SINGLETONS:\n            return  # Allow comparison for types which are not obvious\n        yield match.start(), \"E721 do not compare types, use 'isinstance()'\"\n\n\ndef python_3000_has_key(logical_line):\n    r\"\"\"\n    The {}.has_key() method is removed in the Python 3.\n    Use the 'in' operation instead.\n\n    Okay: if \"alph\" in d:\\n    print d[\"alph\"]\n    W601: assert d.has_key('alph')\n    \"\"\"\n    pos = logical_line.find('.has_key(')\n    if pos > -1:\n        yield pos, \"W601 .has_key() is deprecated, use 'in'\"\n\n\ndef python_3000_raise_comma(logical_line):\n    \"\"\"\n    When raising an exception, use \"raise ValueError('message')\"\n    instead of the older form \"raise ValueError, 'message'\".\n\n    The paren-using form is preferred because when the exception arguments\n    are long or include string formatting, you don't need to use line\n    continuation characters thanks to the containing parentheses.  The older\n    form is removed in Python 3.\n\n    Okay: raise DummyError(\"Message\")\n    W602: raise DummyError, \"Message\"\n    \"\"\"\n    match = RAISE_COMMA_REGEX.match(logical_line)\n    if match and not RERAISE_COMMA_REGEX.match(logical_line):\n        yield match.end() - 1, \"W602 deprecated form of raising exception\"\n\n\ndef python_3000_not_equal(logical_line):\n    \"\"\"\n    != can also be written <>, but this is an obsolete usage kept for\n    backwards compatibility only. New code should always use !=.\n    The older syntax is removed in Python 3.\n\n    Okay: if a != 'no':\n    W603: if a <> 'no':\n    \"\"\"\n    pos = logical_line.find('<>')\n    if pos > -1:\n        yield pos, \"W603 '<>' is deprecated, use '!='\"\n\n\ndef python_3000_backticks(logical_line):\n    \"\"\"\n    Backticks are removed in Python 3.\n    Use repr() instead.\n\n    Okay: val = repr(1 + 2)\n    W604: val = `1 + 2`\n    \"\"\"\n    pos = logical_line.find('`')\n    if pos > -1:\n        yield pos, \"W604 backticks are deprecated, use 'repr()'\"\n\n\n##############################################################################\n# Helper functions\n##############################################################################\n\n\nif '' == ''.encode():\n    # Python 2: implicit encoding.\n    def readlines(filename):\n        f = open(filename)\n        try:\n            return f.readlines()\n        finally:\n            f.close()\n    isidentifier = re.compile(r'[a-zA-Z_]\\w*').match\n    stdin_get_value = sys.stdin.read\nelse:\n    # Python 3\n    def readlines(filename):\n        f = open(filename, 'rb')\n        try:\n            coding, lines = tokenize.detect_encoding(f.readline)\n            f = TextIOWrapper(f, coding, line_buffering=True)\n            return [l.decode(coding) for l in lines] + f.readlines()\n        except (LookupError, SyntaxError, UnicodeError):\n            f.close()\n            # Fall back if files are improperly declared\n            f = open(filename, encoding='latin-1')\n            return f.readlines()\n        finally:\n            f.close()\n    isidentifier = str.isidentifier\n\n    def stdin_get_value():\n        return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()\nreadlines.__doc__ = \"    Read the source code.\"\nnoqa = re.compile(r'# no(?:qa|pep8)\\b', re.I).search\n\n\ndef expand_indent(line):\n    r\"\"\"\n    Return the amount of indentation.\n    Tabs are expanded to the next multiple of 8.\n\n    >>> expand_indent('    ')\n    4\n    >>> expand_indent('\\t')\n    8\n    >>> expand_indent('    \\t')\n    8\n    >>> expand_indent('       \\t')\n    8\n    >>> expand_indent('        \\t')\n    16\n    \"\"\"\n    if '\\t' not in line:\n        return len(line) - len(line.lstrip())\n    result = 0\n    for char in line:\n        if char == '\\t':\n            result = result // 8 * 8 + 8\n        elif char == ' ':\n            result += 1\n        else:\n            break\n    return result\n\n\ndef mute_string(text):\n    \"\"\"\n    Replace contents with 'xxx' to prevent syntax matching.\n\n    >>> mute_string('\"abc\"')\n    '\"xxx\"'\n    >>> mute_string(\"'''abc'''\")\n    \"'''xxx'''\"\n    >>> mute_string(\"r'abc'\")\n    \"r'xxx'\"\n    \"\"\"\n    # String modifiers (e.g. u or r)\n    start = text.index(text[-1]) + 1\n    end = len(text) - 1\n    # Triple quotes\n    if text[-3:] in ('\"\"\"', \"'''\"):\n        start += 2\n        end -= 2\n    return text[:start] + 'x' * (end - start) + text[end:]\n\n\ndef parse_udiff(diff, patterns=None, parent='.'):\n    \"\"\"Return a dictionary of matching lines.\"\"\"\n    # For each file of the diff, the entry key is the filename,\n    # and the value is a set of row numbers to consider.\n    rv = {}\n    path = nrows = None\n    for line in diff.splitlines():\n        if nrows:\n            if line[:1] != '-':\n                nrows -= 1\n            continue\n        if line[:3] == '@@ ':\n            hunk_match = HUNK_REGEX.match(line)\n            row, nrows = [int(g or '1') for g in hunk_match.groups()]\n            rv[path].update(range(row, row + nrows))\n        elif line[:3] == '+++':\n            path = line[4:].split('\\t', 1)[0]\n            if path[:2] == 'b/':\n                path = path[2:]\n            rv[path] = set()\n    return dict([(os.path.join(parent, path), rows)\n                 for (path, rows) in rv.items()\n                 if rows and filename_match(path, patterns)])\n\n\ndef filename_match(filename, patterns, default=True):\n    \"\"\"\n    Check if patterns contains a pattern that matches filename.\n    If patterns is unspecified, this always returns True.\n    \"\"\"\n    if not patterns:\n        return default\n    return any(fnmatch(filename, pattern) for pattern in patterns)\n\n\n##############################################################################\n# Framework to run all checks\n##############################################################################\n\n\n_checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}\n\n\ndef register_check(check, codes=None):\n    \"\"\"\n    Register a new check object.\n    \"\"\"\n    def _add_check(check, kind, codes, args):\n        if check in _checks[kind]:\n            _checks[kind][check][0].extend(codes or [])\n        else:\n            _checks[kind][check] = (codes or [''], args)\n    if inspect.isfunction(check):\n        args = inspect.getargspec(check)[0]\n        if args and args[0] in ('physical_line', 'logical_line'):\n            if codes is None:\n                codes = ERRORCODE_REGEX.findall(check.__doc__ or '')\n            _add_check(check, args[0], codes, args)\n    elif inspect.isclass(check):\n        if inspect.getargspec(check.__init__)[0][:2] == ['self', 'tree']:\n            _add_check(check, 'tree', codes, None)\n\n\ndef init_checks_registry():\n    \"\"\"\n    Register all globally visible functions where the first argument name\n    is 'physical_line' or 'logical_line'.\n    \"\"\"\n    mod = inspect.getmodule(register_check)\n    for (name, function) in inspect.getmembers(mod, inspect.isfunction):\n        register_check(function)\ninit_checks_registry()\n\n\nclass Checker(object):\n    \"\"\"\n    Load a Python source file, tokenize it, check coding style.\n    \"\"\"\n\n    def __init__(self, filename=None, lines=None,\n                 options=None, report=None, **kwargs):\n        if options is None:\n            options = StyleGuide(kwargs).options\n        else:\n            assert not kwargs\n        self._io_error = None\n        self._physical_checks = options.physical_checks\n        self._logical_checks = options.logical_checks\n        self._ast_checks = options.ast_checks\n        self.max_line_length = options.max_line_length\n        self.hang_closing = options.hang_closing\n        self.verbose = options.verbose\n        self.filename = filename\n        if filename is None:\n            self.filename = 'stdin'\n            self.lines = lines or []\n        elif filename == '-':\n            self.filename = 'stdin'\n            self.lines = stdin_get_value().splitlines(True)\n        elif lines is None:\n            try:\n                self.lines = readlines(filename)\n            except IOError:\n                exc_type, exc = sys.exc_info()[:2]\n                self._io_error = '%s: %s' % (exc_type.__name__, exc)\n                self.lines = []\n        else:\n            self.lines = lines\n        if self.lines:\n            ord0 = ord(self.lines[0][0])\n            if ord0 in (0xef, 0xfeff):  # Strip the UTF-8 BOM\n                if ord0 == 0xfeff:\n                    self.lines[0] = self.lines[0][1:]\n                elif self.lines[0][:3] == '\\xef\\xbb\\xbf':\n                    self.lines[0] = self.lines[0][3:]\n        self.report = report or options.report\n        self.report_error = self.report.error\n\n    def report_invalid_syntax(self):\n        exc_type, exc = sys.exc_info()[:2]\n        if len(exc.args) > 1:\n            offset = exc.args[1]\n            if len(offset) > 2:\n                offset = offset[1:3]\n        else:\n            offset = (1, 0)\n        self.report_error(offset[0], offset[1] or 0,\n                          'E901 %s: %s' % (exc_type.__name__, exc.args[0]),\n                          self.report_invalid_syntax)\n    report_invalid_syntax.__doc__ = \"    Check if the syntax is valid.\"\n\n    def readline(self):\n        \"\"\"\n        Get the next line from the input buffer.\n        \"\"\"\n        self.line_number += 1\n        if self.line_number > len(self.lines):\n            return ''\n        return self.lines[self.line_number - 1]\n\n    def readline_check_physical(self):\n        \"\"\"\n        Check and return the next physical line. This method can be\n        used to feed tokenize.generate_tokens.\n        \"\"\"\n        line = self.readline()\n        if line:\n            self.check_physical(line)\n        return line\n\n    def run_check(self, check, argument_names):\n        \"\"\"\n        Run a check plugin.\n        \"\"\"\n        arguments = []\n        for name in argument_names:\n            arguments.append(getattr(self, name))\n        return check(*arguments)\n\n    def check_physical(self, line):\n        \"\"\"\n        Run all physical checks on a raw input line.\n        \"\"\"\n        self.physical_line = line\n        if self.indent_char is None and line[:1] in WHITESPACE:\n            self.indent_char = line[0]\n        for name, check, argument_names in self._physical_checks:\n            result = self.run_check(check, argument_names)\n            if result is not None:\n                offset, text = result\n                self.report_error(self.line_number, offset, text, check)\n\n    def build_tokens_line(self):\n        \"\"\"\n        Build a logical line from tokens.\n        \"\"\"\n        self.mapping = []\n        logical = []\n        comments = []\n        length = 0\n        previous = None\n        for token in self.tokens:\n            token_type, text = token[0:2]\n            if token_type == tokenize.COMMENT:\n                comments.append(text)\n                continue\n            if token_type in SKIP_TOKENS:\n                continue\n            if token_type == tokenize.STRING:\n                text = mute_string(text)\n            if previous:\n                end_row, end = previous[3]\n                start_row, start = token[2]\n                if end_row != start_row:    # different row\n                    prev_text = self.lines[end_row - 1][end - 1]\n                    if prev_text == ',' or (prev_text not in '{[('\n                                            and text not in '}])'):\n                        logical.append(' ')\n                        length += 1\n                elif end != start:  # different column\n                    fill = self.lines[end_row - 1][end:start]\n                    logical.append(fill)\n                    length += len(fill)\n            self.mapping.append((length, token))\n            logical.append(text)\n            length += len(text)\n            previous = token\n        self.logical_line = ''.join(logical)\n        self.noqa = comments and noqa(''.join(comments))\n        # With Python 2, if the line ends with '\\r\\r\\n' the assertion fails\n        # assert self.logical_line.strip() == self.logical_line\n\n    def check_logical(self):\n        \"\"\"\n        Build a line from tokens and run all logical checks on it.\n        \"\"\"\n        self.build_tokens_line()\n        self.report.increment_logical_line()\n        first_line = self.lines[self.mapping[0][1][2][0] - 1]\n        indent = first_line[:self.mapping[0][1][2][1]]\n        self.previous_indent_level = self.indent_level\n        self.indent_level = expand_indent(indent)\n        if self.verbose >= 2:\n            print(self.logical_line[:80].rstrip())\n        for name, check, argument_names in self._logical_checks:\n            if self.verbose >= 4:\n                print('   ' + name)\n            for result in self.run_check(check, argument_names):\n                offset, text = result\n                if isinstance(offset, tuple):\n                    orig_number, orig_offset = offset\n                else:\n                    for token_offset, token in self.mapping:\n                        if offset >= token_offset:\n                            orig_number = token[2][0]\n                            orig_offset = (token[2][1] + offset - token_offset)\n                self.report_error(orig_number, orig_offset, text, check)\n        self.previous_logical = self.logical_line\n\n    def check_ast(self):\n        try:\n            tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)\n        except (SyntaxError, TypeError):\n            return self.report_invalid_syntax()\n        for name, cls, _ in self._ast_checks:\n            checker = cls(tree, self.filename)\n            for lineno, offset, text, check in checker.run():\n                if not noqa(self.lines[lineno - 1]):\n                    self.report_error(lineno, offset, text, check)\n\n    def generate_tokens(self):\n        if self._io_error:\n            self.report_error(1, 0, 'E902 %s' % self._io_error, readlines)\n        tokengen = tokenize.generate_tokens(self.readline_check_physical)\n        try:\n            for token in tokengen:\n                yield token\n        except (SyntaxError, tokenize.TokenError):\n            self.report_invalid_syntax()\n\n    def check_all(self, expected=None, line_offset=0):\n        \"\"\"\n        Run all checks on the input file.\n        \"\"\"\n        self.report.init_file(self.filename, self.lines, expected, line_offset)\n        if self._ast_checks:\n            self.check_ast()\n        self.line_number = 0\n        self.indent_char = None\n        self.indent_level = 0\n        self.previous_logical = ''\n        self.tokens = []\n        self.blank_lines = blank_lines_before_comment = 0\n        parens = 0\n        for token in self.generate_tokens():\n            self.tokens.append(token)\n            token_type, text = token[0:2]\n            if self.verbose >= 3:\n                if token[2][0] == token[3][0]:\n                    pos = '[%s:%s]' % (token[2][1] or '', token[3][1])\n                else:\n                    pos = 'l.%s' % token[3][0]\n                print('l.%s\\t%s\\t%s\\t%r' %\n                      (token[2][0], pos, tokenize.tok_name[token[0]], text))\n            if token_type == tokenize.OP:\n                if text in '([{':\n                    parens += 1\n                elif text in '}])':\n                    parens -= 1\n            elif not parens:\n                if token_type == tokenize.NEWLINE:\n                    if self.blank_lines < blank_lines_before_comment:\n                        self.blank_lines = blank_lines_before_comment\n                    self.check_logical()\n                    self.tokens = []\n                    self.blank_lines = blank_lines_before_comment = 0\n                elif token_type == tokenize.NL:\n                    if len(self.tokens) == 1:\n                        # The physical line contains only this token.\n                        self.blank_lines += 1\n                    self.tokens = []\n                elif token_type == tokenize.COMMENT and len(self.tokens) == 1:\n                    if blank_lines_before_comment < self.blank_lines:\n                        blank_lines_before_comment = self.blank_lines\n                    self.blank_lines = 0\n                    if COMMENT_WITH_NL:\n                        # The comment also ends a physical line\n                        self.tokens = []\n        return self.report.get_file_results()\n\n\nclass BaseReport(object):\n    \"\"\"Collect the results of the checks.\"\"\"\n    print_filename = False\n\n    def __init__(self, options):\n        self._benchmark_keys = options.benchmark_keys\n        self._ignore_code = options.ignore_code\n        # Results\n        self.elapsed = 0\n        self.total_errors = 0\n        self.counters = dict.fromkeys(self._benchmark_keys, 0)\n        self.messages = {}\n\n    def start(self):\n        \"\"\"Start the timer.\"\"\"\n        self._start_time = time.time()\n\n    def stop(self):\n        \"\"\"Stop the timer.\"\"\"\n        self.elapsed = time.time() - self._start_time\n\n    def init_file(self, filename, lines, expected, line_offset):\n        \"\"\"Signal a new file.\"\"\"\n        self.filename = filename\n        self.lines = lines\n        self.expected = expected or ()\n        self.line_offset = line_offset\n        self.file_errors = 0\n        self.counters['files'] += 1\n        self.counters['physical lines'] += len(lines)\n\n    def increment_logical_line(self):\n        \"\"\"Signal a new logical line.\"\"\"\n        self.counters['logical lines'] += 1\n\n    def error(self, line_number, offset, text, check):\n        \"\"\"Report an error, according to options.\"\"\"\n        code = text[:4]\n        if self._ignore_code(code):\n            return\n        if code in self.counters:\n            self.counters[code] += 1\n        else:\n            self.counters[code] = 1\n            self.messages[code] = text[5:]\n        # Don't care about expected errors or warnings\n        if code in self.expected:\n            return\n        if self.print_filename and not self.file_errors:\n            print(self.filename)\n        self.file_errors += 1\n        self.total_errors += 1\n        return code\n\n    def get_file_results(self):\n        \"\"\"Return the count of errors and warnings for this file.\"\"\"\n        return self.file_errors\n\n    def get_count(self, prefix=''):\n        \"\"\"Return the total count of errors and warnings.\"\"\"\n        return sum([self.counters[key]\n                    for key in self.messages if key.startswith(prefix)])\n\n    def get_statistics(self, prefix=''):\n        \"\"\"\n        Get statistics for message codes that start with the prefix.\n\n        prefix='' matches all errors and warnings\n        prefix='E' matches all errors\n        prefix='W' matches all warnings\n        prefix='E4' matches all errors that have to do with imports\n        \"\"\"\n        return ['%-7s %s %s' % (self.counters[key], key, self.messages[key])\n                for key in sorted(self.messages) if key.startswith(prefix)]\n\n    def print_statistics(self, prefix=''):\n        \"\"\"Print overall statistics (number of errors and warnings).\"\"\"\n        for line in self.get_statistics(prefix):\n            print(line)\n\n    def print_benchmark(self):\n        \"\"\"Print benchmark numbers.\"\"\"\n        print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))\n        if self.elapsed:\n            for key in self._benchmark_keys:\n                print('%-7d %s per second (%d total)' %\n                      (self.counters[key] / self.elapsed, key,\n                       self.counters[key]))\n\n\nclass FileReport(BaseReport):\n    \"\"\"Collect the results of the checks and print only the filenames.\"\"\"\n    print_filename = True\n\n\nclass StandardReport(BaseReport):\n    \"\"\"Collect and print the results of the checks.\"\"\"\n\n    def __init__(self, options):\n        super(StandardReport, self).__init__(options)\n        self._fmt = REPORT_FORMAT.get(options.format.lower(),\n                                      options.format)\n        self._repeat = options.repeat\n        self._show_source = options.show_source\n        self._show_pep8 = options.show_pep8\n\n    def init_file(self, filename, lines, expected, line_offset):\n        \"\"\"Signal a new file.\"\"\"\n        self._deferred_print = []\n        return super(StandardReport, self).init_file(\n            filename, lines, expected, line_offset)\n\n    def error(self, line_number, offset, text, check):\n        \"\"\"Report an error, according to options.\"\"\"\n        code = super(StandardReport, self).error(line_number, offset,\n                                                 text, check)\n        if code and (self.counters[code] == 1 or self._repeat):\n            self._deferred_print.append(\n                (line_number, offset, code, text[5:], check.__doc__))\n        return code\n\n    def get_file_results(self):\n        \"\"\"Print the result and return the overall count for this file.\"\"\"\n        self._deferred_print.sort()\n        for line_number, offset, code, text, doc in self._deferred_print:\n            print(self._fmt % {\n                'path': self.filename,\n                'row': self.line_offset + line_number, 'col': offset + 1,\n                'code': code, 'text': text,\n            })\n            if self._show_source:\n                if line_number > len(self.lines):\n                    line = ''\n                else:\n                    line = self.lines[line_number - 1]\n                print(line.rstrip())\n                print(' ' * offset + '^')\n            if self._show_pep8 and doc:\n                print(doc.lstrip('\\n').rstrip())\n        return self.file_errors\n\n\nclass DiffReport(StandardReport):\n    \"\"\"Collect and print the results for the changed lines only.\"\"\"\n\n    def __init__(self, options):\n        super(DiffReport, self).__init__(options)\n        self._selected = options.selected_lines\n\n    def error(self, line_number, offset, text, check):\n        if line_number not in self._selected[self.filename]:\n            return\n        return super(DiffReport, self).error(line_number, offset, text, check)\n\n\nclass StyleGuide(object):\n    \"\"\"Initialize a PEP-8 instance with few options.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        # build options from the command line\n        self.checker_class = kwargs.pop('checker_class', Checker)\n        parse_argv = kwargs.pop('parse_argv', False)\n        config_file = kwargs.pop('config_file', None)\n        parser = kwargs.pop('parser', None)\n        options, self.paths = process_options(\n            parse_argv=parse_argv, config_file=config_file, parser=parser)\n        if args or kwargs:\n            # build options from dict\n            options_dict = dict(*args, **kwargs)\n            options.__dict__.update(options_dict)\n            if 'paths' in options_dict:\n                self.paths = options_dict['paths']\n        self.runner = self.input_file\n        self.options = options\n\n        if not options.reporter:\n            options.reporter = BaseReport if options.quiet else StandardReport\n\n        for index, value in enumerate(options.exclude):\n            options.exclude[index] = value.rstrip('/')\n        options.select = tuple(options.select or ())\n        if not (options.select or options.ignore or\n                options.testsuite or options.doctest) and DEFAULT_IGNORE:\n            # The default choice: ignore controversial checks\n            options.ignore = tuple(DEFAULT_IGNORE.split(','))\n        else:\n            # Ignore all checks which are not explicitly selected\n            options.ignore = ('',) if options.select else tuple(options.ignore)\n        options.benchmark_keys = BENCHMARK_KEYS[:]\n        options.ignore_code = self.ignore_code\n        options.physical_checks = self.get_checks('physical_line')\n        options.logical_checks = self.get_checks('logical_line')\n        options.ast_checks = self.get_checks('tree')\n        self.init_report()\n\n    def init_report(self, reporter=None):\n        \"\"\"Initialize the report instance.\"\"\"\n        self.options.report = (reporter or self.options.reporter)(self.options)\n        return self.options.report\n\n    def check_files(self, paths=None):\n        \"\"\"Run all checks on the paths.\"\"\"\n        if paths is None:\n            paths = self.paths\n        report = self.options.report\n        runner = self.runner\n        report.start()\n        try:\n            for path in paths:\n                if os.path.isdir(path):\n                    self.input_dir(path)\n                elif not self.excluded(path):\n                    runner(path)\n        except KeyboardInterrupt:\n            print('... stopped')\n        report.stop()\n        return report\n\n    def input_file(self, filename, lines=None, expected=None, line_offset=0):\n        \"\"\"Run all checks on a Python source file.\"\"\"\n        if self.options.verbose:\n            print('checking %s' % filename)\n        fchecker = self.checker_class(\n            filename, lines=lines, options=self.options)\n        return fchecker.check_all(expected=expected, line_offset=line_offset)\n\n    def input_dir(self, dirname):\n        \"\"\"Check all files in this directory and all subdirectories.\"\"\"\n        dirname = dirname.rstrip('/')\n        if self.excluded(dirname):\n            return 0\n        counters = self.options.report.counters\n        verbose = self.options.verbose\n        filepatterns = self.options.filename\n        runner = self.runner\n        for root, dirs, files in os.walk(dirname):\n            if verbose:\n                print('directory ' + root)\n            counters['directories'] += 1\n            for subdir in sorted(dirs):\n                if self.excluded(subdir, root):\n                    dirs.remove(subdir)\n            for filename in sorted(files):\n                # contain a pattern that matches?\n                if ((filename_match(filename, filepatterns) and\n                     not self.excluded(filename, root))):\n                    runner(os.path.join(root, filename))\n\n    def excluded(self, filename, parent=None):\n        \"\"\"\n        Check if options.exclude contains a pattern that matches filename.\n        \"\"\"\n        if not self.options.exclude:\n            return False\n        basename = os.path.basename(filename)\n        if filename_match(basename, self.options.exclude):\n            return True\n        if parent:\n            filename = os.path.join(parent, filename)\n        return filename_match(filename, self.options.exclude)\n\n    def ignore_code(self, code):\n        \"\"\"\n        Check if the error code should be ignored.\n\n        If 'options.select' contains a prefix of the error code,\n        return False.  Else, if 'options.ignore' contains a prefix of\n        the error code, return True.\n        \"\"\"\n        return (code.startswith(self.options.ignore) and\n                not code.startswith(self.options.select))\n\n    def get_checks(self, argument_name):\n        \"\"\"\n        Find all globally visible functions where the first argument name\n        starts with argument_name and which contain selected tests.\n        \"\"\"\n        checks = []\n        for check, attrs in _checks[argument_name].items():\n            (codes, args) = attrs\n            if any(not (code and self.ignore_code(code)) for code in codes):\n                checks.append((check.__name__, check, args))\n        return sorted(checks)\n\n\ndef get_parser(prog='pep8', version=__version__):\n    parser = OptionParser(prog=prog, version=version,\n                          usage=\"%prog [options] input ...\")\n    parser.config_options = [\n        'exclude', 'filename', 'select', 'ignore', 'max-line-length',\n        'hang-closing', 'count', 'format', 'quiet', 'show-pep8',\n        'show-source', 'statistics', 'verbose']\n    parser.add_option('-v', '--verbose', default=0, action='count',\n                      help=\"print status messages, or debug with -vv\")\n    parser.add_option('-q', '--quiet', default=0, action='count',\n                      help=\"report only file names, or nothing with -qq\")\n    parser.add_option('-r', '--repeat', default=True, action='store_true',\n                      help=\"(obsolete) show all occurrences of the same error\")\n    parser.add_option('--first', action='store_false', dest='repeat',\n                      help=\"show first occurrence of each error\")\n    parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE,\n                      help=\"exclude files or directories which match these \"\n                           \"comma separated patterns (default: %default)\")\n    parser.add_option('--filename', metavar='patterns', default='*.py',\n                      help=\"when parsing directories, only check filenames \"\n                           \"matching these comma separated patterns \"\n                           \"(default: %default)\")\n    parser.add_option('--select', metavar='errors', default='',\n                      help=\"select errors and warnings (e.g. E,W6)\")\n    parser.add_option('--ignore', metavar='errors', default='',\n                      help=\"skip errors and warnings (e.g. E4,W)\")\n    parser.add_option('--show-source', action='store_true',\n                      help=\"show source code for each error\")\n    parser.add_option('--show-pep8', action='store_true',\n                      help=\"show text of PEP 8 for each error \"\n                           \"(implies --first)\")\n    parser.add_option('--statistics', action='store_true',\n                      help=\"count errors and warnings\")\n    parser.add_option('--count', action='store_true',\n                      help=\"print total number of errors and warnings \"\n                           \"to standard error and set exit code to 1 if \"\n                           \"total is not null\")\n    parser.add_option('--max-line-length', type='int', metavar='n',\n                      default=MAX_LINE_LENGTH,\n                      help=\"set maximum allowed line length \"\n                           \"(default: %default)\")\n    parser.add_option('--hang-closing', action='store_true',\n                      help=\"hang closing bracket instead of matching \"\n                           \"indentation of opening bracket's line\")\n    parser.add_option('--format', metavar='format', default='default',\n                      help=\"set the error format [default|pylint|<custom>]\")\n    parser.add_option('--diff', action='store_true',\n                      help=\"report only lines changed according to the \"\n                           \"unified diff received on STDIN\")\n    group = parser.add_option_group(\"Testing Options\")\n    if os.path.exists(TESTSUITE_PATH):\n        group.add_option('--testsuite', metavar='dir',\n                         help=\"run regression tests from dir\")\n        group.add_option('--doctest', action='store_true',\n                         help=\"run doctest on myself\")\n    group.add_option('--benchmark', action='store_true',\n                     help=\"measure processing speed\")\n    return parser\n\n\ndef read_config(options, args, arglist, parser):\n    \"\"\"Read both user configuration and local configuration.\"\"\"\n    config = RawConfigParser()\n\n    user_conf = options.config\n    if user_conf and os.path.isfile(user_conf):\n        if options.verbose:\n            print('user configuration: %s' % user_conf)\n        config.read(user_conf)\n\n    parent = tail = args and os.path.abspath(os.path.commonprefix(args))\n    while tail:\n        if config.read([os.path.join(parent, fn) for fn in PROJECT_CONFIG]):\n            if options.verbose:\n                print('local configuration: in %s' % parent)\n            break\n        parent, tail = os.path.split(parent)\n\n    pep8_section = parser.prog\n    if config.has_section(pep8_section):\n        option_list = dict([(o.dest, o.type or o.action)\n                            for o in parser.option_list])\n\n        # First, read the default values\n        new_options, _ = parser.parse_args([])\n\n        # Second, parse the configuration\n        for opt in config.options(pep8_section):\n            if options.verbose > 1:\n                print(\"  %s = %s\" % (opt, config.get(pep8_section, opt)))\n            if opt.replace('_', '-') not in parser.config_options:\n                print(\"Unknown option: '%s'\\n  not in [%s]\" %\n                      (opt, ' '.join(parser.config_options)))\n                sys.exit(1)\n            normalized_opt = opt.replace('-', '_')\n            opt_type = option_list[normalized_opt]\n            if opt_type in ('int', 'count'):\n                value = config.getint(pep8_section, opt)\n            elif opt_type == 'string':\n                value = config.get(pep8_section, opt)\n            else:\n                assert opt_type in ('store_true', 'store_false')\n                value = config.getboolean(pep8_section, opt)\n            setattr(new_options, normalized_opt, value)\n\n        # Third, overwrite with the command-line options\n        options, _ = parser.parse_args(arglist, values=new_options)\n    options.doctest = options.testsuite = False\n    return options\n\n\ndef process_options(arglist=None, parse_argv=False, config_file=None,\n                    parser=None):\n    \"\"\"Process options passed either via arglist or via command line args.\"\"\"\n    if not arglist and not parse_argv:\n        # Don't read the command line if the module is used as a library.\n        arglist = []\n    if not parser:\n        parser = get_parser()\n    if not parser.has_option('--config'):\n        if config_file is True:\n            config_file = DEFAULT_CONFIG\n        group = parser.add_option_group(\"Configuration\", description=(\n            \"The project options are read from the [%s] section of the \"\n            \"tox.ini file or the setup.cfg file located in any parent folder \"\n            \"of the path(s) being processed.  Allowed options are: %s.\" %\n            (parser.prog, ', '.join(parser.config_options))))\n        group.add_option('--config', metavar='path', default=config_file,\n                         help=\"user config file location (default: %default)\")\n    options, args = parser.parse_args(arglist)\n    options.reporter = None\n\n    if options.ensure_value('testsuite', False):\n        args.append(options.testsuite)\n    elif not options.ensure_value('doctest', False):\n        if parse_argv and not args:\n            if options.diff or any(os.path.exists(name)\n                                   for name in PROJECT_CONFIG):\n                args = ['.']\n            else:\n                parser.error('input not specified')\n        options = read_config(options, args, arglist, parser)\n        options.reporter = parse_argv and options.quiet == 1 and FileReport\n\n    options.filename = options.filename and options.filename.split(',')\n    options.exclude = options.exclude.split(',')\n    options.select = options.select and options.select.split(',')\n    options.ignore = options.ignore and options.ignore.split(',')\n\n    if options.diff:\n        options.reporter = DiffReport\n        stdin = stdin_get_value()\n        options.selected_lines = parse_udiff(stdin, options.filename, args[0])\n        args = sorted(options.selected_lines)\n\n    return options, args\n\n\ndef _main():\n    \"\"\"Parse options and run checks on Python source.\"\"\"\n    pep8style = StyleGuide(parse_argv=True, config_file=True)\n    options = pep8style.options\n    if options.doctest or options.testsuite:\n        from testsuite.support import run_tests\n        report = run_tests(pep8style)\n    else:\n        report = pep8style.check_files()\n    if options.statistics:\n        report.print_statistics()\n    if options.benchmark:\n        report.print_benchmark()\n    if options.testsuite and not options.quiet:\n        report.print_results()\n    if report.total_errors:\n        if options.count:\n            sys.stderr.write(str(report.total_errors) + '\\n')\n        sys.exit(1)\n\nif __name__ == '__main__':\n    _main()\n"
  },
  {
    "path": "utils/git-hooks/pre-commit",
    "content": "#!/usr/bin/env python\nfrom difflib import unified_diff as differ\nimport os\nfrom subprocess import check_output as call, CalledProcessError\nimport sys\nimport shutil\n\n\ndef read(filepath):\n    mode = \"b\" if sys.platform.startswith(\"win\") else \"\"\n    data = \"\"\n    with open(filepath, \"rU\" + mode) as fd:\n        data = fd.read()\n    return data\n\n\ndef get_current_revision():\n    cmd = \"git rev-parse --verify HEAD\".split(\" \")\n    gitrev = \"\".join(r.strip() for r in call(cmd).split(\"\\n\") if r.strip())\n    return gitrev\n\n\ndef get_commit_files():\n    gitrev = get_current_revision()\n    cmd = \"git diff-index --cached %s\" % gitrev\n    cmd = cmd.split(\" \")\n    gitdata = call(cmd).split(\"\\n\")\n    gitfiles = []\n    for gdata in gitdata:\n        if gdata != '':\n            gdata = gdata.split()\n            if gdata[4] in ['A', 'M', 'C']:\n                gitfiles.append(gdata[5])\n    return gitfiles\n\n\ndef get_project_path():\n    cmd = \"git rev-parse --show-toplevel\".split(\" \")\n    project_path = \"\".join(p.strip()\n                           for p in call(cmd).split(\"\\n\")\n                           if p.strip())\n    return project_path\n\n\ndef get_hooks_path():\n    gitpath = get_project_path()\n    hookspath = os.path.join(gitpath, 'utils', 'git-hooks')\n    if not hookspath:\n        hookspath = os.getcwd()\n    return hookspath\n\n\ndef get_subhooks(hookspath, gitpath, fname):\n    sub_hooks = []\n    for root, folders, files in os.walk(hookspath):\n        for filename in files:\n            hookpath = os.path.join(gitpath, root, filename)\n            if filename.startswith(fname) and filename != fname:\n                sub_hooks.append(hookpath)\n    return sub_hooks\n\n\ndef check_for_update():\n    fname = os.path.basename(__file__)\n    gitpath = get_project_path()\n    old_path = os.path.join(gitpath, '.git', 'hooks', fname)\n    new_path = os.path.join(gitpath, 'utils', 'git-hooks', fname)\n    old_data = read(old_path)\n    new_data = read(new_path)\n    diff = list(differ(old_data.splitlines(),\n                       new_data.splitlines(),\n                       old_path, new_path))\n    changed = '\\n'.join(diff)\n    if changed:\n        shutil.copyfile(new_path, old_path)\n        shutil.copymode(new_path, old_path)\n        shutil.copystat(new_path, old_path)\n        print >> sys.stderr, \"%s updated.  Please re-run.\" % fname\n        sys.exit(1)\n\n\ndef run_sub_hooks():\n    fname = os.path.basename(__file__)\n    gitrev = get_current_revision()\n    gitfiles = get_commit_files()\n    gitpath = get_project_path()\n    hookspath = get_hooks_path()\n    sub_hooks = get_subhooks(hookspath, gitpath, fname)\n    stop_commit = False\n    for hookpath in sub_hooks:\n        for gitfile in gitfiles:\n            fpath = os.path.join(gitpath, gitfile)\n            cmd = [hookpath, fpath]\n            try:\n                output = call(cmd)\n            except CalledProcessError as e:\n                print e\n                sys.exit(1)\n            if output:\n                print output\n                stop_commit = True\n    if stop_commit:\n        print \"Please re-run commit to capture changes\"\n        sys.exit(1)\n\n\nif __name__ == \"__main__\":\n    check_for_update()\n    run_sub_hooks()\n"
  },
  {
    "path": "utils/git-hooks/pre-commit_check-for-cpp-style",
    "content": "#!/usr/bin/env python\nfrom cpplint.cpplint import main\n\nif __name__ == \"__main__\":\n    main()"
  },
  {
    "path": "utils/git-hooks/pre-commit_check-for-pdb",
    "content": "#!/usr/bin/env python\n\"\"\"\nUsage:\n    check-for-pdb <filepath>\n\n\"\"\"\nfrom difflib import unified_diff as differ\nimport sys\nfrom xml.etree import cElementTree as ElementTree\n\n\ndef check_for_pdb(filepath):\n    mode = \"b\" if sys.platform.startswith('win') else \"\"\n    has_pdb_string = \"\"\n    with open(filepath, \"rU\" + mode) as fd:\n        has_pdb_string = fd.read()\n    if \"import pdb\" in has_pdb_string:\n        print >> sys.stderr, \"Error: '%s' has a pdb\" % filepath\n        sys.exit(1)\n\n\nif __name__ == \"__main__\":\n    import sys\n\n    argv = sys.argv[1:] if len(sys.argv) > 1 else []\n    if not argv:\n        print __doc__\n        sys.exit(1)\n    else:\n        filepath = argv[0]\n        extensions_to_convert = ('py')\n        if filepath.endswith(extensions_to_convert):\n            check_for_pdb(filepath)\n"
  },
  {
    "path": "utils/git-hooks/pre-commit_pep8",
    "content": "#!/usr/bin/env python\n\"\"\"\nUsage:\n    check-for-pep8 <filepath>\n\n\"\"\"\nfrom difflib import unified_diff as differ\nimport sys\nfrom xml.etree import cElementTree as ElementTree\n\nfrom pep8 import _main as main\n\n\ndef check_for_pep8(filepath):\n    main()\n    mode = \"b\" if sys.platform.startswith('win') else \"\"\n    has_pdb_string = \"\"\n    with open(filepath, \"rU\" + mode) as fd:\n        has_pdb_string = fd.read()\n    if \"import pdb\" in has_pdb_string:\n        print >> sys.stderr, \"Error: '%s' has a pdb\" % filepath\n        sys.exit(1)\n\n\nif __name__ == \"__main__\":\n    import sys\n\n    argv = sys.argv[1:] if len(sys.argv) > 1 else []\n    if not argv:\n        print __doc__\n        sys.exit(1)\n    else:\n        filepath = argv[0]\n        extensions_to_convert = ('py')\n        if filepath.endswith(extensions_to_convert):\n            check_for_pep8(filepath)\n"
  },
  {
    "path": "utils/git-hooks/pre-commit_pretty-xml",
    "content": "#!/usr/bin/env python\n\"\"\"\nUsage:\n    pretty-xml <filepath>\n\n\"\"\"\nfrom difflib import unified_diff as differ\nimport os\nimport re\nimport sys\nfrom xml.etree import cElementTree as ElementTree\n\n\ndef pretty_xml(filepath):\n    mode = \"b\" if sys.platform.startswith('win') else \"\"\n    ugly_xml_string = \"\"\n    with open(filepath, \"rU\" + mode) as fd:\n        ugly_xml_string = fd.read()\n    patt = r'>\\n\\s+([^<>\\s].*?)\\n\\s+</'\n    repl = r'>\\g<1></'\n    pretty_xml_string = re.sub(patt, repl, ugly_xml_string, re.DOTALL)\n    # remove extra whitespace\n    pretty_xml_string = \"\\n\".join(l.rstrip()\n                                  for l in pretty_xml_string.split('\\n')\n                                  if l.strip())\n    diff = list(differ(ugly_xml_string.splitlines(),\n                       pretty_xml_string.splitlines(),\n                       filepath, filepath))\n    changed = '\\n'.join(diff)\n    if changed:\n        xml_node = ElementTree.fromstring(pretty_xml_string)\n        ms_namespace = \"http://schemas.microsoft.com/developer/msbuild/2003\"\n        ElementTree.register_namespace('', ms_namespace)\n        kwargs = dict(encoding='utf-8', method='xml', xml_declaration=True)\n        xml_tree = ElementTree.ElementTree(xml_node)\n        xml_tree.write(filepath, **kwargs)\n        print \"Beautified XML:\", filepath\n\n\nif __name__ == \"__main__\":\n    import sys\n\n    argv = sys.argv[1:] if len(sys.argv) > 1 else []\n    if not argv:\n        print __doc__\n        sys.exit(1)\n    else:\n        filepath = argv[0]\n        extensions_to_convert = ('vcxproj', 'vcxproj.filters', 'csproj', 'xml')\n        if filepath.endswith(extensions_to_convert):\n            pretty_xml(filepath)\n"
  },
  {
    "path": "utils/git-hooks/pre-commit_strip-eol-spaces",
    "content": "#!/usr/bin/env python\n\"\"\"\nUsage:\n    strip-eol-spaces <filepath>\n\n\"\"\"\nfrom difflib import unified_diff as differ\nimport sys\nfrom xml.etree import cElementTree as ElementTree\n\n\ndef strip_eol_spaces(filepath):\n    mode = \"b\" if sys.platform.startswith('win') else \"\"\n    extra_space_string = \"\"\n    with open(filepath, \"rU\" + mode) as fd:\n        extra_space_string = fd.read()\n    compact_string = extra_space_string.rstrip()\n    diff = list(differ(extra_space_string.splitlines(),\n                       compact_string.splitlines(),\n                       filepath, filepath))\n    changed = '\\n'.join(diff)\n    if changed:\n        with open(filepath, 'w' + mode) as fd:\n            fd.write(compact_string)\n        print \"Striped extra EOL Spaces:\", filepath\n\n\nif __name__ == \"__main__\":\n    import sys\n\n    argv = sys.argv[1:] if len(sys.argv) > 1 else []\n    if not argv:\n        print __doc__\n    else:\n        filepath = argv[0]\n        extensions_to_convert = ('c', 'cpp', 'h', 'hpp', 'cs', 'py',\n                                 'vcxproj', 'vcxproj.filters', 'xml')\n        if filepath.endswith(extensions_to_convert):\n            strip_eol_spaces(filepath)\n"
  },
  {
    "path": "utils/git-hooks/pre-commit_tabs-to-spaces",
    "content": "#!/usr/bin/env python\n\"\"\"\nUsage:\n    tabs-to-spaces <filepath>\n\n\"\"\"\nfrom difflib import unified_diff as differ\nimport sys\nfrom xml.etree import cElementTree as ElementTree\n\n\ndef tabs_to_spaces(filepath):\n    mode = \"b\" if sys.platform.startswith('win') else \"\"\n    tabbed_string = \"\"\n    with open(filepath, \"rU\" + mode) as fd:\n        tabbed_string = fd.read()\n    special = ('vcxproj', 'vcxproj.filters', 'xml')\n    spacing = 4 if not filepath.endswith(special) else 2\n    untabbed_string = tabbed_string.expandtabs(spacing)\n    diff = list(differ(tabbed_string.splitlines(),\n                       untabbed_string.splitlines(),\n                       filepath, filepath))\n    changed = '\\n'.join(diff)\n    if changed:\n        with open(filepath, 'w' + mode) as fd:\n            fd.write(untabbed_string)\n        print \"Tabs to Spaces:\", filepath\n\n\nif __name__ == \"__main__\":\n    import sys\n\n    argv = sys.argv[1:] if len(sys.argv) > 1 else []\n    if not argv:\n        print __doc__\n    else:\n        filepath = argv[0]\n        extensions_to_convert = ('c', 'cpp', 'h', 'hpp', 'cs', 'py',\n                                 'vcxproj', 'vcxproj.filters', 'xml')\n        if filepath.endswith(extensions_to_convert):\n            tabs_to_spaces(filepath)\n"
  }
]